diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100755 index 00000000..e75f4044 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,24 @@ +FROM gcr.io/diamond-privreg/xchem/ccp4:7.1 as ccp4 +FROM gcr.io/diamond-privreg/xchem/phenix:1.20 as phenix + +FROM buildpack-deps:bullseye-curl as devel + +COPY --from=ccp4 /ccp4-7.1 /ccp4-7.1 +COPY --from=phenix /phenix-1.20 /phenix-1.20 + +RUN apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y \ + libxrender1 libfontconfig libxext6 \ + libglib2.0-0 libsm6 libxi6 libxrandr2 libxfixes3 libxcursor1 libxinerama1 \ + libgomp1 libxdamage1 libxcb-shm0 libxcb-render0 \ + python3-pip \ + && apt-get clean -y && rm -rf /var/lib/apt/lists/* \ + && echo . /ccp4-7.1/bin/ccp4.setup-sh | tee ~/.bashrc ~/.zshrc \ + && curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o /tmp/get-pip.py \ + && /ccp4-7.1/bin/ccp4-python /tmp/get-pip.py \ + && /ccp4-7.1/bin/ccp4-python -m pip install flake8 \ + && pip3 install black[python2] + +ENV QT_X11_NO_MITSHM=1 \ + PATH=$PATH:/ccp4-7.1/bin:/phenix-1.20/build/bin diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 00000000..4f29d49d --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,9 @@ +{ + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "version": "2.4.3", + "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:e9e1d402031416ed5fc500f242c27ffa1043a27b5ba612e6596ea62503c8ae70", + "integrity": "sha256:e9e1d402031416ed5fc500f242c27ffa1043a27b5ba612e6596ea62503c8ae70" + } + } +} \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100755 index 00000000..c17d3c9d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,40 @@ +{ + "name": "XChemExplorer", + "build": { + "dockerfile": "Dockerfile", + "target": "devel" + }, + "remoteEnv": { + "XChemExplorer_DIR": "${localWorkspaceFolder}", + "SLURM_USER": "${localEnv:USER", + "DISPLAY": "${localEnv:DISPLAY}" + }, + "customizations": { + "vscode": { + "settings": { + "python.defaultInterpreterPath": "/ccp4-7.1/bin/ccp4-python" + }, + "extensions": [ + "ms-python.python@2021.9.1246542782" + ] + } + }, + "features": { + "ghcr.io/devcontainers/features/common-utils:2": {} + }, + "initializeCommand": "bash -c 'for i in $HOME/.inputrc; do [ -f $i ] || touch $i; done'", + "runArgs": [ + "--net=host", + "--security-opt=label=type:container_runtime_t" + ], + "mounts": [ + "source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind", + "source=${localEnv:HOME}/.inputrc,target=/root/.inputrc,type=bind", + "source=/dls/labxchem/data/,target=/dls/labxchem/data/,type=bind" + ], + "remoteUser": "root", + "containerUser": "root", + "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind", + "workspaceFolder": "${localWorkspaceFolder}", + "postCreateCommand": "pip install -e ." +} \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100755 index 00000000..69ba180e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +*.pyc +*.egg-info +/build +/dist + +__pycache__/ +.pytest_cache/ +.mypy_cache/ + +xce.log + +/.devcontainer +/.git + +Dockerfile diff --git a/.github/workflows/code.yaml b/.github/workflows/code.yaml new file mode 100755 index 00000000..5030df19 --- /dev/null +++ b/.github/workflows/code.yaml @@ -0,0 +1,38 @@ +name: Code CI + +on: + push: + branches: + - master + tags: + - "*" + pull_request: + +jobs: + lint: + runs-on: "ubuntu-latest" + container: + image: python:2.7.18-buster + steps: + - name: Checkout Source + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install pip3 + run: | + apt-get update + apt-get install -y python3-pip + + - name: Install linters + run: | + pip install flake8 + pip3 install black[python2] + + - name: Lint with flake8 + run: | + flake8 . + + - name: Lint with black + run: | + black --check . diff --git a/.gitignore b/.gitignore index 6ed3aa79..add26d82 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ -**/*.pyc *.pyc -XChemExplorer_dmd.sh -.idea +*.egg-info +/build +/dist + +__pycache__/ +.pytest_cache/ +.mypy_cache/ + +xce.log diff --git a/.travis.yml b/.travis.yml deleted file mode 100755 index ae77ee17..00000000 --- a/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -sudo: required -services: docker -install: docker build -t reskyner/xce . -script: docker run reskyner/xce /bin/bash -c "/ccp4/bin/ccp4-python /XChemExplorer/compile_test.py" diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100755 index 00000000..e5c03dda --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "XCE", + "type": "python", + "request": "launch", + "module": "xce", + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100755 index 00000000..29bffb55 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "python.pythonPath": "/ccp4-7.1/bin/ccp4-python", + "python.defaultInterpreterPath": "/ccp4-7.1/bin/ccp4-python", + "python.linting.enabled": true, + "python.linting.flake8Enabled": true, + "python.linting.flake8Path": "/ccp4-7.1/bin/flake8", + "python.formatting.provider": "black", + "python.formatting.blackPath": "/usr/local/bin/black", +} \ No newline at end of file diff --git a/ChangeLog.txt b/ChangeLog.txt index 70296500..fa93cc14 100755 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,364 @@ +v1.9.4 (10/10/2022) +- catch unusual space group names in PDB CRYST card + +v1.9.3 (29/06/2022) +- added 'module load ccp4/7.1.018' to grade script otherwise the helper script will run with python3 + +v1.9.2 (28/06/2022) +- replace obsolete 'source /dls/science/groups/i04-1/software/pandda-update/ccp4/ccp4-7.0/bin/ccp4.setup-sh' with 'module load ccp4/7.1.016' before running pandda.export + + +v1.9.1 (16/06/2022) +- changed add instances of 'module load ccp4' to 'module load ccp4/7.1.018', except for the pandda2 function + +v1.9.0 (22/04/2022) +- add functionality for running PanDDA2 at Diamond Light Source +- fixed hyperlink to PanDDA manual + +v1.8.2 (20/01/2022) +- added 'Porphyromonas gingivalis' to NCBI taxonomy id +- fixed SARS-CoV-2 name in NCBI taxonomy id table +- bug fix: XChemDeposit - added missing underscore to loop statement in _pdbx_audit_support block +- XChemDeposit: issue warning and do not add empty xtal string to error list +- bug fix: XChemDeposit - recognition of staraniso logfile + +v1.8.1 (19/01/2022) +- fix: event map to sf conversion; ignore existing ligand pdb files + +v1.8.0 (17/12/2021) +- added feature for working with cocktails/ combi-soaks: multiple compounds/ smiles separated by semi-colon in db are recognised during restraint generation + +v1.7.36 (13/10/2021) +- bug fix: manual selection of different auto-processing results with same pipeline +- removed obsolete paths used for parsing of auto-processing results + +v1.7.35 (13/10/2021) +- ignore json merging statistics and xia2.mmcif if aimless.log exists + +v1.7.34 (25/06/2021) +- added pdbx_audit_support category for funding agency now required for PDB deposition + +v1.7.33 (02/02/2021) +- bug fix: enable RefinementParameters button in XChemCOOT + +v1.7.32 (24/01/2021) +- bug fix: XChemDeposit - enable reading of not symlinked logfiles + +v1.7.31 (20/01/2021) +- bug fix: XChemDeposit - enable reading of staraniso .table1 file + +v1.7.30 (17/12/2020) +- bug fix in XChemDeposit + +v1.7.29 (09/12/2020) +- bug fix: syntax error in XChemDeposit +- XChemDeposit: use default pdb_extract if no installation in XChemExplorer_dir + +v1.7.28 (25/11/2020) +- added exception to catch 'Cannot allocate memory' error in XChemMain.get_gda_barcodes + +v1.7.27 (24/11/2020) +- bug fix: add missing DataProcessingUniqueReflectionsLow/High column to db + +v1.7.26 (12/11/2020) +- XChemDeposit: remove \n and \r from smiles string in _diffrn.details + +v1.7.25 (11/11/2020) +- convert json logfile from dials into pseudo aimless file for mmcif file preparation (required for pdb-extract) + +v1.7.24 (02/11/2020) +- capitalized organism names in NCBI_taxonomy_ID dictionary + +v1.7.23 (02/11/2020) +- pandda refinement: stopped sourcing obsolete pandda v0.2.12 at DLS (otherwise refinement update script fails due to missing gemmi library) + +v1.7.22 (28/10/2020) +- cosmetic changes to deposition interface +- bug fix: make event map assignment during MMCIF preparation backward compatible +- bug fix: finding of event map with highest CC for given ligand + +v1.7.21 (19/10/2020) +- bug fix: use default CCP4 for giant.merge_conformations + +v1.7.20 (16/10/2020) +- bug fix: remove undocumented and faulty changes to RunQuickRefine + +v1.7.19 (12/10/2020) +- bug fix: use 'module load ccp4/7.0.072' for pandda.analyse, but 'module load ccp4' (i.e. v7.1) for pre-run ground-state selection at DLS + +v1.7.18 (12/10/2020) +- bug fix: added missing 'module load ccp4' statement when generating pandda.analyse shell script at DLS + +v1.7.17 (09/10/2020) +- bug fix: corrected positions of ignore checkboxes in pandda.analyse + +v1.7.16 (08/10/2020) +- enable export of selected datasets with pandda.export +- glitch fix: remove hydrogens before saving model for buster refinement (causes problems during ligand occupancy refinement) +- XChemRefine: removed "-q medium.q" option for non-DLS refinement +- added helper script to which reverts to last successful non-pandda refinement +- XChemCoot (pandda refinement): reading of (2)fofc.maps disabled because Coot 0.9 does not handle P1 maps well +- pandda.analyse: stopped sourcing obsolete pandda v0.2.12 at DLS + +v1.7.15 (25/09/2020) +- added option to ignore GELLY sanity check in BUSTER +- added option to ignore GELLY sanity check during pandda export with BUSTER + +v1.7.14 (24/09/2020) +- added option for ligand occupancy refinement in BUSTER +- XChemCootBuster: reading of (2)fofc.maps disabled because Coot 0.9 does not handle P1 maps well + +v1.7.13 (23/09/2020) +- bug fix: use wavelength read from (.free).mtz during model MMCIF preparation when updating SF MMCIF + +v1.7.12 (14/09/2020) +- bug fix: problem with recognizing AIMLESS logfiles during preparation of MMCIF files +- bug fix: try finding experimental wavelength from .free.mtz file if it is 0.0 in refine.mtz during MMCIF file preparation +- preparation of mmcif files: catch and report missing event mtz files + +v1.7.11 (09/09/2020) +- bug fix: preparation of mmcif files: run aimless in onlymerge mode if only json file available + +v1.7.10 (08/09/2020) +- bug fix - preparation of mmcif files for deposition: enable usage of event mtz files which were generated during 'BUSTER' export routine + +v1.7.9 (03/09/2020) +- change 'Open COOT' to 'Open COOT - REFMAC refinement -' in Refinement action box + +v1.7.8 (01/09/2020) +- bug fix: string formatting error during restraints generation on local machine +- added scanchirals option to rhofit command in fit_ligands function +- bug fix: added 'module load buster' to fit_ligands function + +v1.7.7 (22/07/2020) +- bug fix: logical error in creation of restraints script when adding 'module load ccp4/phenix' command +- removed phenix.reduce step from restraints generation + +v1.7.6 (22/07/2020) +- bug fix: added 'module load ccp4/phenix' to restraints script in case not part of user bashrc file + +v1.7.5 (21/07/2020) +- bug fix: remove obsolete 'module load mx' statement from xce_ script which currently loads a gemmi incompatible ccp4 version + +v1.7.4 (21/07/2020) +- bug fix: selected results not linked after parsing of auto-processing results +- enabled updates of message & progress bar during scoring of auto-processing results +- enabled updates of message & progress bar during DB update of pinIDs + +v1.7.3 (20/07/2020) +- bug fix: ignore large temporary files in get_gda_barcodes which lead to memory errors +- removed obsolete PROASIS menu item +- bug fix: xce now reads already parsed auto-processing results correctly to speed up parsing + +v1.7.2 (16/07/2020) +- show molprobity to-do list generated by buster-report in XCE COOT interface + +v1.7.1 (13/07/2020) +- select auto-refinement from action box not from preferences + +v1.7.0 (29/06/2020) +- implemented new pandda export routine which takes advantage of gemmi +- updated html export accordingly +- bug fix: order of commands changed in buster.sh to enable buster-report run on DLS cluster +- added links to buster-reports in refinement table +- calculate (2)fofc maps around ligand with ending _cut.ccp4 +- calculate ligand CC with EDSTATS and display in refinement table + +v1.6.29 (28/06/2020) +- added capture of person (and date) changing RefinementOutcome field in DB + +v1.6.28 (28/06/2020) +- added capture of refiner and date of refinement in DB after refinement + +v1.6.27 (28/06/2020) +- made water update optional when refining with with Buster + +v1.6.26 (24/06/2020) +- added option for anisotropic B-factor refinement with Buster + +v1.6.25 (22/06/2020) +- backup soakDB after restart and 'update database from filesystem' + +v1.6.24 (22/06/2020) +- bug fix: missing '\n' in calculate_maps (XChemRefine) deleted soakDB file + +v1.6.23 (12/06/2020) +- use gemmi (if available) to convert event maps to mtz + +v1.6.22 (11/06/2020) +- added mapmask step after map calculation in buster refinement in order to cover entire molecule (required for nglview) + +v1.6.21 (04/06/2020) +- source ccp4 7.0 at Diamond before running giant.score_model during Buster refinement + +v1.6.20 (03/06/2020) +- enable remote cluster submission of (Buster) refinement jobs + +v1.6.19 (28/05/2020) +- combined parsing of 'agamemnon' auto-collection into single function + +v1.6.18 (17/05/2020) +- removed dls specific source files from pandda.analyse script when running on local machine + +v1.6.17 (17/05/2020) +- DIMPLE: added 'tolerance 5' keyword to pointless step to allow reindexing in case of slightly larger unit cell differences + +v1.6.16 (12/05/2020) +- XChemExplorer.py removed unused 'import gtk' statement which is incompatible with ccp4 7.1 + +v1.6.15 (12/05/2020) +- added html summary for all '5-deposition ready' structures +- HTML summary: show NO_SPIDER_PLOT_AVAILABLE.png if spider plot is missing + +v1.6.14 (11/05/2020) +- XChemUtils: get BUSTER from PROGRAM REMARK +- XChemDeposit: usage of model mmcif file disabled because of unclear errors during group deposition +- XChemDeposit: do not add ligand cif to model mmcif because Buster does already include it +- XChemDeposit: use pdb_extract v3.26 when using mmcif instead of pdb files + +v1.6.13 (10/05/2020) +- XChemDeposit: use RefinementMMCIFmodel_latest (if available) instead of refine.split.bound-state.pdb + +v1.6.12 (09/05/2020) +- capture refinement mmcif file location in DB after refinement (if available) + +v1.6.11 (04/05/2020) +- added giant.score_model after buster refinement +- added field and capture of path to buster-reports in DB + +v1.6.10 (04/05/2020) +- bug fix: only read (2)fofc_twin.map during dimple_twin map review + +v1.6.9 (04/05/2020) +- added COOT command to open dimple_twin maps + +v1.6.8 (30/04/2020) +- enable html export of '4 - CompChem ready' structures only + +v1.6.7 (29/04/2020) +- initial twin refinement with dimple in separate folder and additional fields in XChemDB + +v1.6.6 (28/04/2020) +- bug fix: NameError in XChemRefine + +v1.6.5 (28/04/2020) +- more verbose error messages in buster refine module + +v1.6.4 (28/04/2020) +- added validation with buster-reports after refinement with buster + +v1.6.3 (25/04/2020) +- grade will use mogul for restraints generation if program available + +v1.6.2 (24/04/2020) +- restraints generation: use program name in script name for easier trouble-shooting +- assign_stereochemistry.py option removed from restraints generation + +v1.6.1 (17/04/2020) +- added 7 - Analysed & Rejected' to refinement table combobox + +v1.6.0 (14/04/2020) +- new option: directly refine bound-state only after pandda.inspect with buster + +v1.5.17 (07/04/2020) +- add option to specify $SampleID in structure deposition title + +v1.5.16 (06/04/2020) +- XChemThread: copy un-merged MTZ file for xia2, dials & 3d(ii) +- XChemThread: change parsing of auto-processing results to enable reading of multiple runs with same name, e.g. xia-3dii +- bug fix: enable 3dii only selection of auto-processing results +- remove xia2-3d only auto-processing selection option + +v1.5.15 (06/04/2020) +- bug fix: found instance in pandda_inspect_events.csv where sites/ events displayed as float instead of int; added fix + +v1.5.14 (14/03/2020) +- HTML export: enable changing of contour level of event maps +- HTML export: set ligand confidence to "not assigned" for deposition ready model that have "0 - no ligand bound" + +v1.5.13 (11/03/2020) +- bug fix: include covlinks argument is None in XChemPANDDA quickRefine + +v1.5.12 (10/03/2020) +- DIMPLE: added pointless step before dimple to reindex according to ref_pdb if necessary + +v1.5.11 (10/03/2020) +- added linking of covalent binders for PanDDA models (refine.split-bound.pdb) +- remove links to refine.output... PDB files after refinement + +v1.5.10 (05/03/2020) +- bug fix: correct name of event map in files directory + +v1.5.9 (05/03/2020) +- bug fix: reading of .json scaling logfiles enabled during 'update database from filesystem' + +v1.5.8 (04/03/2020) +- added Taxonomy ID for mus musculus + +v1.5.7 (03/03/2020) +- bug fix: capture all available event maps during html export + +v1.5.6 (02/03/2020) +- added Taxonomy ID for BAT SARS-LIKE CORONAVIRUS and COVID-19 + +v1.5.5 (27/02/2020) +- bug fix: update depositTable with ground_state_sf.mmcif if successfully created + +v1.5.4 (27/02/2020) +- bug fix: iotbx spg symbol for H32 needed changing for unique step of initial map calculation + +v1.5.3 (26/02/2020) +- bug fix: read spacegroup as H32 from xia2.mmcif ('R 3 2 :H') + +v1.5.2 (25/02/2020) +- bug fix: correct determination of staraniso runs for different space groups + +v1.5.1 (24/02/2020) +- enable parsing of autoPROC/ staraniso auto-processing results with specific space groups applied (e.g. autoPROC-P21) +- bug fix: names of auto-processing pipelines get now correctly determined + +v1.5.0 (20/02/2020) +- ground-state mean maps are EXCLUDED from apo deposition, because either map2mtz conversion was faulty or columns were missing; moreover, they are not required to reproduce the maps and users can deposit them separately on ZENODO if they want + +v1.4.10 (18/02/2020) +- XChemDeposit: remove _pdbx_related_exp_data_set block because PanDDA ZENODO upload is not required +- XChemDeposit: add _pdbx_contact_author.identifier_ORCID field +- XChemDeposit: add pdbx_keywords dropdown +- added helper script to reset occupancy of all protein residues with single conformer to 1.00 +- XChemDeposit: add ligand cif file to structure mmcif file + +v1.4.9 (13/02/2020) +- bug fix: corrected DataProcessingUnitCellVolume calculation from merging-statistics.json file for trigonal lattice +- show only 'resolution high' in tables because formatting for resolution at 1.5 or 2.0 I/sig(I) inconsistent in aimless logfiles and not reported in dials scaling logile + +v1.4.8 (07/02/2020) +- bug fix: default labxchem folders are only selected if xce starts in /dls/labxchem/...; just having labxchem in current directory string is not sufficient + +v1.4.7 (07/02/2020) +- added script to helpers which can replace residues in bound and ground state based on a new reference model (change_residues_in_ground_and_bound-state.py); cannot be called from GUI at the moment + +v1.4.6 (21/01/2020) +- added xia2-* wildcard to read_write_autoprocessing_results_from_to_disc because autoprocessing folder names changed +- added parsing of DIALS JSON merging statistics file and MMCIF cell parameter file +- added 'recollect' folder for parsing of auto-collections + +v1.4.5 (16/01/2020) +- bug fix: removing and re-parsing of folders from project directory does not need the DataProcessingAutoAssigned flag to be reset if the MTZ file does not exist + +v1.4.4 (10/01/2020) +- bug fix: corrected pandda.analyse keyword 'exclude_from_z_map_analysis' + +v1.4.3 (10/01/2020) +- added additional error message during pandda.export in case of missing ensemble model + +v1.4.2 (17/12/2019) +- bug fix: arbitrary clicking order for atoms making a new covalent link + +v1.4.1 (16/12/2019) +- bug fix: in helpers/assign_stereochemistry.py; use CompoundSMILES instead of CompoundSMILESproduct (which need to be provided by user) +- bug fix: auto-fitting of ligands - use default ccp4 distribition and submission command +- bug fix: add 'module load mx' to restraints generation script; uses default ccp4 installation, otherwise CLIB path for GRADE broken + v1.4.0 (03/12/2019) - introduced simple semantic versioning according to https://semver.org diff --git a/Dockerfile b/Dockerfile index e6c7441f..5eacd4cd 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,24 @@ -FROM reskyner/ccp4 -#RUN apt-get install -f libxcursor-dev -ADD ./run_tests . -ADD ./compile_test.py . -RUN mkdir XChemExplorer -ADD * /XChemExplorer/ -#CMD ccp4-python ./compile_tests.py +FROM gcr.io/diamond-privreg/xchem/ccp4:7.1 as ccp4 +FROM gcr.io/diamond-privreg/xchem/phenix:1.20 as phenix + +FROM registry.hub.docker.com/library/debian:bullseye as xce + +COPY --from=ccp4 /ccp4-7.1 /ccp4-7.1 + +ARG XCE_DIR=/xce +WORKDIR ${XCE_DIR} + +COPY . ${XCE_DIR} + +RUN apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y \ + libxrender1 libfontconfig libxext6 \ + libglib2.0-0 libsm6 libxi6 libxrandr2 libxfixes3 libxcursor1 libxinerama1 \ + libgomp1 libxdamage1 libxcb-shm0 libxcb-render0 \ + && apt-get clean -y && rm -rf /var/lib/apt/lists/* + +ENV QT_X11_NO_MITSHM=1 \ + XChemExplorer_DIR=${XCE_DIR} + +ENTRYPOINT /ccp4-7.1/bin/ccp4-python -m xce diff --git a/README.md b/README.md index 72593cbd..1893ce41 100755 --- a/README.md +++ b/README.md @@ -135,3 +135,8 @@ ccp4-python -m pip install panddas (Note, this is not supported – you really are on your own! Recommended only for geeks.) 3. If your IT team doesn’t want to help you, try setting up a virtual machine – then you have root permissions and can do whatever you like. Performance ought to be okay. + + +## License + +XChemExplorer is licensed under the MIT license. diff --git a/XChemExplorer b/XChemExplorer deleted file mode 120000 index 05c692a5..00000000 --- a/XChemExplorer +++ /dev/null @@ -1 +0,0 @@ -XChemExplorer_dmd.sh \ No newline at end of file diff --git a/XChemExplorer.py b/XChemExplorer.py deleted file mode 100755 index b5eabe8a..00000000 --- a/XChemExplorer.py +++ /dev/null @@ -1,5041 +0,0 @@ -######################################################################################################################## -# DEVELOPER README: # -# This is the main script, where the GUI is initialised from. All of the main layout objects live in their own scripts # -# under ./gui_scripts (i.e. the tab content). The settings and preferences script sets up all of the directory paths # -# and contains dictionaries defining the top menu, push buttons and the tables held in the main tabs. The layout # -# script contains functions for performing simple layout tasks, such as adding a combobox, and contains init. # -# functions for all of the main layout functions. # -# # -# In the future, the functions associated with buttons and frames etc. should be moved into the relevant script, but # -# this is a bit more complicated. For now, they are separated out into sections within this script. The only GUI stuff # -# going on in here is calling the initialisation functions. To change the layout of a tab, edit it in it's own script, # -# and add any new functions in this script, in the relevant section. (If there is one yet) # -# # -# There's still a lot of cleaning up to be done in the future... # -######################################################################################################################## - -# solve gtk startup error -import gtk - -gtk.set_interactive(False) - -import base64 -import getpass -import glob -import math -import multiprocessing -import pickle -import subprocess -import sys, os -import webbrowser -from datetime import datetime -from PyQt4 import QtGui, QtCore, QtWebKit - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'lib')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'web')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) - -from settings_preferences import * -from layout import * -from stylesheet import set_stylesheet - - -from XChemUtils import parse -import XChemThread -import XChemDB -import XChemPANDDA -import XChemToolTips -import XChemMain -import XChemPlots -import XChemLog -import XChemProcess -import XChemDeposit -import XChemWeb - -import matplotlib.pyplot as plt -from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas - -class XChemExplorer(QtGui.QApplication): - def __init__(self, args): - - # init a QApplication object to hold XCE - QtGui.QApplication.__init__(self, args) - - # start GUI - self.start_GUI() - - # set stylesheet - how the gui looks - set_stylesheet(self) - - self.exec_() - - def start_GUI(self): - - # check http://doc.qt.io/qt-4.8/stylesheet-customizing.html#the-box-model - # This needs moving somewhere more appropriate... - self.headlineLabelfont = QtGui.QFont("Arial", 20, QtGui.QFont.Bold) - - setup().settings(self) - setup().preferences(self) - setup().tables(self) - - self.layout_funcs = LayoutFuncs() - - # GUI setup - self.window = QtGui.QWidget() - self.window.setWindowTitle("XChemExplorer") - self.screen = QtGui.QDesktopWidget().screenGeometry() - - LayoutObjects(self).workflow(self) - LayoutObjects(self).main_layout(self) - LayoutFuncs().add_widgets_layouts(self) - - self.checkLabXChemDir() - - def checkLabXChemDir(self): - dirCheck = QtGui.QMessageBox() - dirCheckLayout = dirCheck.layout() - vbox = QtGui.QVBoxLayout() - try: - warning = ( - 'Are you sure you want to launch XCE here:\n\n' - +self.labxchem_directory_current+'\n\n' - 'If this is not where you should be running XCE, please close!\n' - ) - except AttributeError: - return - vbox.addWidget(QtGui.QLabel(warning)) - dirCheckLayout.addLayout(vbox, 0, 0) - dirCheck.exec_(); - - - # function to update datasource - def datasource_menu_reload_samples(self): - self.update_log.insert( - 'reading samples from data source: ' + os.path.join(self.database_directory, self.data_source_file)) - self.update_status_bar( - 'reading samples from data source: ' + os.path.join(self.database_directory, self.data_source_file)) - self.update_header_and_data_from_datasource() - self.update_all_tables() - self.overview_datasource_table.resizeColumnsToContents() - - # function to create new datasource - def create_new_data_source(self): - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'Save file', self.database_directory)) - # make sure that the file always has .sqlite extension - if file_name.rfind('.') != -1: - file_name = file_name[:file_name.rfind('.')] + '.sqlite' - else: - file_name = file_name + '.sqlite' - self.db = XChemDB.data_source(file_name) - print('==> XCE: creating new data source') - self.db.create_empty_data_source_file() - self.db.create_missing_columns() - self.database_directory = file_name[:file_name.rfind('/')] - self.data_source_file = file_name[file_name.rfind('/') + 1:] - self.data_source_file_label.setText(os.path.join(self.database_directory, self.data_source_file)) - self.settings['database_directory'] = self.database_directory - self.settings['data_source'] = self.data_source_file - self.data_source_set = True - self.datasource_menu_reload_samples() - - - #################################################################################################################### - # # - # DATASETS TAB # - # # - #################################################################################################################### - def continously_check_for_new_data_collection(self, state): - self.timer_to_check_for_new_data_collection.timeout.connect( - lambda: self.check_for_new_autoprocessing_or_rescore(False)) - if state == QtCore.Qt.Checked: - print('==> XCE: checking automatically every 120s for new data collection') - self.timer_to_check_for_new_data_collection.start(120000) - else: - print('==> XCE: stopped checking for new data collections') - self.timer_to_check_for_new_data_collection.stop() - - def target_selection_combobox_activated(self, text): - self.target = str(text) - - def select_diffraction_data_directory(self): - self.diffraction_data_directory = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - self.diffraction_data_dir_label.setText(self.diffraction_data_directory) - self.settings['diffraction_data_directory'] = self.diffraction_data_directory - self.update_log.insert('setting diffraction data directory to ' + self.diffraction_data_directory) - - def search_for_datasets(self): - self.update_log.insert('search diffraction data directory for datasets...') - print('will search ' + str(self.diffraction_data_directory)) - self.work_thread = XChemMain.find_diffraction_image_directory_fast(self.diffraction_data_directory) - self.explorer_active = 1 - - self.connect(self.work_thread, QtCore.SIGNAL("update_datasets_reprocess_table"), - self.update_datasets_reprocess_table) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - - self.work_thread.start() - - #self.work_thread = self.update_datasets_reprocess_table(self.diffraction_data_directory) - - def translate_datasetID_to_sampleID(self): - translate = QtGui.QMessageBox() - translateLayout = translate.layout() - self.translate_datasetID_to_sampleID_file = '-' - vbox = QtGui.QVBoxLayout() - button = QtGui.QPushButton('Open CSV') - button.clicked.connect(self.open_csv_file_translate_datasetID_to_sampleID) - vbox.addWidget(button) - self.translate_datasetID_to_sampleID_csv_label = QtGui.QLabel(self.translate_datasetID_to_sampleID_file) - vbox.addWidget(self.translate_datasetID_to_sampleID_csv_label) - translateLayout.addLayout(vbox, 0, 0) - translate.addButton(QtGui.QPushButton('OK'), QtGui.QMessageBox.YesRole) - translate.addButton(QtGui.QPushButton('Cancel'), QtGui.QMessageBox.RejectRole) - reply = translate.exec_(); - if reply == 0: - if os.path.isfile(self.translate_datasetID_to_sampleID_file): - trans_dict = {} - for line in open(self.translate_datasetID_to_sampleID_file): - if len(line.split(',')) == 2: - dataset = line.split(',')[0] - new_sample_id = line.split(',')[1] - trans_dict[dataset] = new_sample_id - if len(trans_dict) >= 1: - allRows = self.datasets_reprocess_table.rowCount() - for row in xrange(0, allRows): - dataset_id = str(self.datasets_reprocess_table.item(row, 0).text()) - sample_id = str(self.datasets_reprocess_table.item(row, 1).text()) - if dataset_id in trans_dict: - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(trans_dict[dataset_id]) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.datasets_reprocess_table.setItem(row, 1, cell_text) - self.update_log.insert( - 'dataset: {0!s} -> changing sampleID to: {1!s}'.format(dataset_id, - trans_dict[dataset_id])) - - def select_sample_for_xia2(self): - indexes = self.datasets_reprocess_table.selectionModel().selectedRows() - for index in sorted(indexes): - xtal = str(self.datasets_reprocess_table.item(index.row(), 1).text()) - print(xtal, self.diffraction_data_table_dict[xtal][0]) - self.update_log.insert('{0!s} marked for reprocessing'.format(index.row())) - self.diffraction_data_table_dict[xtal][0].setChecked(True) - - def select_reprocess_reference_mtz(self): - self.update_log.insert('trying to set new reference mtz file for reprocessing with xia2') - file_name = str(QtGui.QFileDialog.getOpenFileName(self.window, 'Select file', self.database_directory)) - if os.path.isfile(file_name): - if file_name.endswith('.mtz'): - self.diffraction_data_reference_mtz = file_name - self.update_log.insert( - 'new reference file for data processing with xia2: ' + self.diffraction_data_reference_mtz) - self.reprocess_reference_mtz_file_label.setText(self.diffraction_data_reference_mtz) - else: - self.update_log.insert('this does not seem to be a mtz file: ' + file_name) - - def check_for_new_autoprocessing_or_rescore(self, rescore_only): - self.update_log.insert('checking for new data collection') - start_thread = False - if rescore_only: - # first pop up a warning message as this will overwrite all user selections - msgBox = QtGui.QMessageBox() - msgBox.setText("*** WARNING ***\nThis will overwrite all your manual selections!\nDo you want to continue?") - msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - start_thread = True - else: - start_thread = False - else: - start_thread = True - - if start_thread: - if self.target == '=== SELECT TARGET ===': - msgBox = QtGui.QMessageBox() - warning = ('*** WARNING ***\n' - 'Please select a target or\n' - 'select "=== project directory ===" if you want to read reprocessed results\n' - 'In case target list is empty, make sure that you have selected the actual\n' - 'data collection visit (e.g. /dls/i04-1/data/2018/lb18145-70)' ) - msgBox.setText(warning) - start_thread = False - -# msgBox.setText(warning) -# msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) -# msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) -# reply = msgBox.exec_(); -# if reply == 0: -# start_thread = True -# else: -# start_thread = False -# else: -# start_thread = True - - if start_thread: - self.work_thread = XChemThread.read_autoprocessing_results_from_disc(self.visit_list, - self.target, - self.reference_file_list, - self.database_directory, - self.data_collection_dict, - self.preferences, - self.datasets_summary_file, - self.initial_model_directory, - rescore_only, - self.acceptable_low_resolution_limit_for_data, - os.path.join(self.database_directory, - self.data_source_file), - self.xce_logfile) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("create_widgets_for_autoprocessing_results_only"), - self.create_widgets_for_autoprocessing_results_only) - self.work_thread.start() - - - ################################################################################################################# - # - # - # - # => for new module from hell - # > start - - def update_gdaLog_parsing_instructions_and_score(self, gdaLogInstructions): - self.gdaLogInstructions = gdaLogInstructions - self.select_best_autoprocessing_result() - - def read_pinIDs_from_gda_logs(self): - self.update_log.insert('reading pinIDs from gda logfiles...') - visit, beamline = XChemMain.getVisitAndBeamline(self.beamline_directory) - self.work_thread = XChemThread.read_pinIDs_from_gda_logs(beamline, - visit, - os.path.join( - self.database_directory, - self.data_source_file), - self.gdaLogInstructions, - self.xce_logfile) - - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("update_gdaLog_parsing_instructions_and_score"), - self.update_gdaLog_parsing_instructions_and_score) - self.work_thread.start() - - - def check_for_new_autoprocessing_results(self): - self.update_log.insert('checking for new data collection') - if self.target == '=== SELECT TARGET ===': - self.update_log.error('NO TARGET SELECTED, PLEASE SELECT A TARGET AND TRY AGAIN!') - start_thread = False - elif self.target == '=== project directory ===': - processedDir = self.initial_model_directory - start_thread = True - elif self.read_agamemnon.isChecked(): - tmp = '/'.join(self.beamline_directory.split('/')[:6]) - processedDir = tmp[:tmp.rfind('-')] -# processedDir = os.path.join(self.beamline_directory[:self.beamline_directory.rfind('-') + 1] + '*/processed/agamemnon/'+self.target) -# processedDir = os.path.join(self.beamline_directory[:self.beamline_directory.rfind('-') + 1] + '*/processed/*/'+self.target) - start_thread = True - else: - processedDir = os.path.join(self.beamline_directory, 'processed', self.target) - start_thread = True - - if start_thread: -# processedDir=os.path.join(self.beamline_directory,'processed',self.target) - self.work_thread = XChemThread.read_write_autoprocessing_results_from_to_disc(processedDir, - os.path.join( - self.database_directory, - self.data_source_file), - self.initial_model_directory, - self.xce_logfile, - self.target, - self.read_agamemnon.isChecked()) - - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("read_pinIDs_from_gda_logs"), - self.read_pinIDs_from_gda_logs) - self.work_thread.start() - - def select_best_autoprocessing_result(self): - if self.rescore: - # first pop up a warning message as this will overwrite all user selections - msgBox = QtGui.QMessageBox() - msgBox.setText("*** WARNING ***\nThis will overwrite all your manual selections!\nDo you want to continue?") - msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply != 0: - start_thread = False - else: - start_thread = True - else: - start_thread = True - - if start_thread: - self.update_log.insert('selecting best autoprocessing result') - self.update_log.insert('samples where user made manual changes will be ignored!') - - if self.target == '=== project directory ===': - processedDir = self.initial_model_directory - else: - processedDir = os.path.join(self.beamline_directory, 'processed', self.target) - - visit,beamline = XChemMain.getVisitAndBeamline(processedDir) - - if self.read_agamemnon.isChecked(): - visit = [] - for v in glob.glob( - os.path.join(self.beamline_directory[:self.beamline_directory.rfind('-') + 1] + '*')): - visit.append(v[v.rfind('/') + 1:]) - - self.work_thread = XChemThread.choose_autoprocessing_outcome(os.path.join(self.database_directory, - self.data_source_file), - visit, - self.reference_file_list, - self.preferences, - self.initial_model_directory, - self.rescore, - self.xce_logfile, - self.read_agamemnon.isChecked()) - - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("populate_datasets_summary_table_NEW"), - self.populate_datasets_summary_table_NEW) - self.work_thread.start() - - # < end - ################################################################################################################### - - - #################################################################################################################### - # # - # MAPS TAB # - # # - #################################################################################################################### - def set_new_reference_if_applicable(self): - print('hallo') - reference_root = str(self.reference_file_selection_combobox.currentText()) - pg_ref = '' - ucVol_ref = 0.0 - for reference in self.reference_file_list: - print(reference[0], reference_root) - if reference[0] == reference_root: - pg_ref = reference[5] - ucVol_ref = reference[4] - break - if ucVol_ref == 0.0: - self.update_log.insert('cannot set reference file since unit cell volume of reference pdb is 0!') - return - - for xtal in self.initial_model_dimple_dict: - reference_file_selection_combobox = self.initial_model_dimple_dict[xtal][1] - self.populate_reference_combobox(reference_file_selection_combobox) - db_dict = self.xtal_db_dict[xtal] - pg_xtal = db_dict['DataProcessingPointGroup'] - ucVol_xtal = db_dict['DataProcessingUnitCellVolume'] - - try: - difference = math.fabs(1 - (float(ucVol_xtal) / float(ucVol_ref))) * 100 - except ValueError: - self.update_log.insert(xtal + ' -> cannot calculate unit cell volume difference') - continue - - if pg_xtal == pg_ref and difference < self.allowed_unitcell_difference_percent: - print(xtal, pg_xtal, ucVol_xtal) - index = reference_file_selection_combobox.findText(reference_root, QtCore.Qt.MatchFixedString) - reference_file_selection_combobox.setCurrentIndex(index) - self.update_log.insert(xtal + ' -> setting ' + reference_root + ' as input PDB file for DIMPLE') - - def refresh_reference_file_list(self): - self.reference_file_list = self.get_reference_file_list(' ') - self.populate_reference_combobox(self.reference_file_selection_combobox) - - def on_context_menu_initial_model(self, point): - # show context menu - self.popMenu_for_maps_table.exec_(self.sender().mapToGlobal(point)) - - #################################################################################################################### - # # - # PANDDA TAB # - # # - #################################################################################################################### - def select_pandda_input_template(self): - mtzin = '' - filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Select Example PDB or MTZ File', - self.initial_model_directory, '*.pdb;;*.mtz') - filepath = str(tuple(filepath_temp)[0]) - pdbin = filepath.split('/')[-1] - if filepath.endswith('.pdb'): - pdbin = filepath.split('/')[-1] - mtzin_temp = pdbin.replace('.pdb', '.mtz') - if os.path.isfile(filepath.replace(pdbin, mtzin_temp)): - mtzin = mtzin_temp - else: - mtzin = '' - if filepath.endswith('.mtz'): - mtzin = filepath.split('/')[-1] - pdbin_temp = pdbin.replace('.mtz', '.pdb') - if os.path.isfile(filepath.replace(mtzin, pdbin_temp)): - pdbin = pdbin_temp - else: - pdbin = '' - - try: - self.pandda_input_data_dir_entry.setText( - '/'+os.path.join(*filepath.split('/')[0:len(filepath.split('/'))-2])) - except TypeError: - self.update_log.error('directory selection invalid') -# if len(filepath.split('/')) - len(self.initial_model_directory.split('/')) == 2: -# self.pandda_input_data_dir_entry.setText(os.path.join(self.initial_model_directory, '*')) -# elif len(filepath.split('/')) - len(self.initial_model_directory.split('/')) > 2: -# subdir = os.path.join( -# *filepath.split('/')[len(self.initial_model_directory.split('/')) + 1:len(filepath.split('/')) - 1]) -# self.pandda_input_data_dir_entry.setText(os.path.join(self.initial_model_directory, '*', subdir)) -# else: -# pass - self.pandda_pdb_style_entry.setText(pdbin) - self.pandda_mtz_style_entry.setText(mtzin) - - def change_pandda_spg_label(self): - combo_text = str(self.pandda_reference_file_selection_combobox.currentText()) - for file in self.reference_file_list: - if file[0] == combo_text: - self.pandda_reference_file_spg_label.setText(file[1]) - break - - def on_context_menu_pandda(self, point): - # show context menu - self.popMenu_for_pandda_table.exec_(self.sender().mapToGlobal(point)) - - #################################################################################################################### - # # - # DEPO TAB # - # # - #################################################################################################################### - def export_to_html(self): - XChemWeb.export_to_html(self.html_export_directory, - self.initial_model_directory, - os.path.join(self.database_directory, self.data_source_file), - self.xce_logfile).prepare() - -# self.update_log.insert('exporting contents of SQLite database into ' + self.html_export_directory) -# os.system( -# 'ccp4-python ' + os.getenv('XChemExplorer_DIR') + '/web/process_sqlite.py -t Summary -s ' + os.path.join( -# self.database_directory, self.data_source_file) + ' -d ' + self.html_export_directory) -# XChemWeb.create_ICM_input_file(self.html_export_directory, -# os.path.join(self.database_directory, self.data_source_file)) -# self.update_log.insert('open ICMpro:') -# self.update_log.insert('/dls/science/groups/i04-1/software/icm-3.8-5/icm64 -g') -# self.update_log.insert('open file browser and navigate to ' + self.html_export_directory) -# self.update_log.insert('drag and drop dsEvent_sqlite.icm into the main window') -# self.update_log.insert('the script will appear in the Workspace Panel') -# self.update_log.insert('right click on the script and select RUN') -# self.update_log.insert('be patient, this may take a while, depending on the number of events') -# self.status_bar.showMessage('please check terminal window for further information') - - def select_ground_state_pdb(self): - p = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Select File', os.getcwd(),'*.pdb') - pdb = str(tuple(p)[0]) - self.ground_state_pdb_button_label.setText(pdb) - - def select_ground_state_mtz(self): - m = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Select File', os.getcwd(),'*.mtz') - mtz = str(tuple(m)[0]) - self.ground_state_mtz_button_label.setText(mtz) - - def add_ground_state_db(self): - db_dict = {'DimplePANDDApath': self.panddas_directory, - 'PDB_file': str(self.ground_state_pdb_button_label.text()), - 'MTZ_file': str(self.ground_state_mtz_button_label.text())} - self.db.create_or_remove_missing_records_in_depositTable(self.xce_logfile, 'ground_state', 'ground_state', - db_dict) - - def prepare_ground_state_mmcif(self): - self.update_log.insert('preparing mmcif file for apo structure deposition') - self.prepare_models_for_deposition_ligand_bound('ground-state') - - def open_icm(self): - self.update_log.insert('starting ICM...') - self.work_thread = XChemThread.start_ICM(self.html_export_directory) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def prepare_files_for_zenodo_upload(self): - self.update_log.insert('preparing files for ZENODO upload...') - os.system('ccp4-python ' + os.getenv( - 'XChemExplorer_DIR') + '/helpers/prepare_for_zenodo_upload.py ' + self.html_export_directory) - - def update_html_for_zenodo_upload(self): - try: - uploadID = int(self.zenodo_upload_id_entry.text()) - self.update_log.insert('updating html files for ZENODO upload,...') - self.update_log.insert('ZENODO upload = ' + str(uploadID)) - os.system('ccp4-python ' + os.getenv( - 'XChemExplorer_DIR') + '/helpers/prepare_for_zenodo_upload.py {0!s} {1!s}'.format( - self.html_export_directory, uploadID)) - except ValueError: - self.update_log.insert('zenodo upload ID must be an integer!') - - #################################################################################################################### - # # - # SETTINGS TAB # - # # - #################################################################################################################### - def settings_button_clicked(self): - if self.sender().text() == 'Select Project Directory': - self.initial_model_directory = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - self.initial_model_directory_label.setText(self.initial_model_directory) - self.pandda_input_data_dir_entry.setText(self.initial_model_directory) - self.settings['initial_model_directory'] = self.initial_model_directory - if self.sender().text() == 'Select Reference Structure Directory': - reference_directory_temp = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - if reference_directory_temp != self.reference_directory: - self.reference_directory = reference_directory_temp - self.update_reference_files(' ') - self.reference_directory_label.setText(self.reference_directory) - self.settings['reference_directory'] = self.reference_directory - if self.sender().text() == 'Select Data Source File': - filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Select File', - self.database_directory, '*.sqlite') - filepath = str(tuple(filepath_temp)[0]) - self.data_source_file = filepath.split('/')[-1] - self.database_directory = filepath[:filepath.rfind('/')] - self.settings['database_directory'] = self.database_directory - self.settings['data_source'] = os.path.join(self.database_directory, self.data_source_file) - write_enabled = self.check_write_permissions_of_data_source() - if not write_enabled: - self.data_source_set = False - else: - self.data_source_set = True - self.data_source_file_label.setText(os.path.join(self.database_directory, self.data_source_file)) - self.db = XChemDB.data_source(os.path.join(self.database_directory, self.data_source_file)) - self.db.create_missing_columns() - self.datasource_menu_reload_samples() - if self.sender().text() == 'Select Data Collection Directory': - dir_name = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - if dir_name != self.beamline_directory: - self.beamline_directory = dir_name - self.target_list, self.visit_list = XChemMain.get_target_and_visit_list(self.beamline_directory,self.read_agamemnon.isChecked()) - self.populate_target_selection_combobox(self.target_selection_combobox) - self.beamline_directory_label.setText(self.beamline_directory) - self.settings['beamline_directory'] = self.beamline_directory - - if self.sender().text() == 'Select Existing\nCollection Summary File': - if self.datasets_summary_file != '': - filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Select File', - self.datasets_summary_file[ - :self.datasets_summary_file.rfind( - '/')], '*.pkl') - else: - filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Select File', os.getcwd(), - '*.pkl') - filepath = str(tuple(filepath_temp)[0]) - self.datasets_summary_file = filepath - self.datasets_summary_file_label.setText(self.datasets_summary_file) - self.settings['datasets_summary'] = self.datasets_summary_file - - if self.sender().text() == 'Assign New\nCollection Summary File': - if self.datasets_summary_file != '': - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'New file', - self.datasets_summary_file[ - :self.datasets_summary_file.rfind('/')])) - else: - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'New file', self.current_directory)) - # make sure that the file always has .pkl extension - if str(file_name).rfind('.') != -1: - file_name = file_name[:file_name.rfind('.')] + '.pkl' - else: - file_name = file_name + '.pkl' - self.datasets_summary_file = file_name - self.datasets_summary_file_label.setText(self.datasets_summary_file) - self.settings['datasets_summary'] = self.datasets_summary_file - - if self.sender().text() == 'Select CCP4_SCR Directory': - self.ccp4_scratch_directory = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - self.ccp4_scratch_directory_label.setText(self.ccp4_scratch_directory) - self.settings['ccp4_scratch'] = self.ccp4_scratch_directory - if self.sender().text() == 'Select PanDDA Directory': - self.panddas_directory = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - self.panddas_directory_label.setText(self.panddas_directory) - self.pandda_output_data_dir_entry.setText(self.panddas_directory) - self.ground_state_pandda_directory_label.setText(self.panddas_directory) - print('PANDDA', self.panddas_directory) - self.settings['panddas_directory'] = self.panddas_directory - - self.layout_funcs.pandda_html(self) - - if self.sender().text() == 'Select HTML Export Directory': - self.html_export_directory = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - self.html_export_directory_label.setText(self.html_export_directory) - self.settings['html_export_directory'] = self.html_export_directory - - if self.sender().text() == 'Select Group deposition Directory': - self.group_deposit_directory = str(QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory")) - self.group_deposition_directory_label.setText(self.group_deposit_directory) - self.settings['group_deposit_directory'] = self.group_deposit_directory - - #self.datasource_menu_reload_samples() - - - - ######################################### sort stuff below here #################################################### - def select_sample_for_dimple(self): - indexes = self.maps_table.selectionModel().selectedRows() - for index in sorted(indexes): - xtal = str(self.maps_table.item(index.row(), 0).text()) - self.update_log.insert('{0!s} is marked for DIMPLE'.format(index.row())) - self.initial_model_dimple_dict[xtal][0].setChecked(True) - - def update_summary_plot(self): - if self.data_source_set: - XChemPlots.summary_plot(os.path.join(self.database_directory, self.data_source_file), - self.overview_axes).update_overview() - self.overview_canvas.draw() - - def show_preferences(self): - preferences = QtGui.QMessageBox() - preferencesLayout = preferences.layout() - - vbox = QtGui.QVBoxLayout() - settings_hbox_filename_root = QtGui.QHBoxLayout() - filename_root_label = QtGui.QLabel('filename root:') - settings_hbox_filename_root.addWidget(filename_root_label) - filename_root_input = QtGui.QLineEdit() - filename_root_input.setFixedWidth(400) - filename_root_input.setText(str(self.filename_root)) - filename_root_input.textChanged[str].connect(self.change_filename_root) - settings_hbox_filename_root.addWidget(filename_root_input) - vbox.addLayout(settings_hbox_filename_root) - - settings_hbox_adjust_allowed_unit_cell_difference = QtGui.QHBoxLayout() - adjust_allowed_unit_cell_difference_label = QtGui.QLabel( - 'Max. Allowed Unit Cell Difference between Reference and Target (%):') - settings_hbox_adjust_allowed_unit_cell_difference.addWidget(adjust_allowed_unit_cell_difference_label) - adjust_allowed_unit_cell_difference = QtGui.QLineEdit() - adjust_allowed_unit_cell_difference.setFixedWidth(200) - adjust_allowed_unit_cell_difference.setText(str(self.allowed_unitcell_difference_percent)) - adjust_allowed_unit_cell_difference.textChanged[str].connect(self.change_allowed_unitcell_difference_percent) - settings_hbox_adjust_allowed_unit_cell_difference.addWidget(adjust_allowed_unit_cell_difference) - vbox.addLayout(settings_hbox_adjust_allowed_unit_cell_difference) - - settings_hbox_acceptable_low_resolution_limit = QtGui.QHBoxLayout() - adjust_acceptable_low_resolution_limit_label = QtGui.QLabel( - 'Acceptable low resolution limit for datasets (in Angstrom):') - settings_hbox_acceptable_low_resolution_limit.addWidget(adjust_acceptable_low_resolution_limit_label) - adjust_acceptable_low_resolution_limit = QtGui.QLineEdit() - adjust_acceptable_low_resolution_limit.setFixedWidth(200) - adjust_acceptable_low_resolution_limit.setText(str(self.acceptable_low_resolution_limit_for_data)) - adjust_acceptable_low_resolution_limit.textChanged[str].connect(self.change_acceptable_low_resolution_limit) - settings_hbox_acceptable_low_resolution_limit.addWidget(adjust_acceptable_low_resolution_limit) - vbox.addLayout(settings_hbox_acceptable_low_resolution_limit) - - vbox_data = QtGui.QVBoxLayout() - vbox_data.addWidget( - QtGui.QLabel('Select amount of processed data you wish to copy to initial_model directory:')) - self.preferences_data_to_copy_combobox = QtGui.QComboBox() - for item in self.preferences_data_to_copy: - self.preferences_data_to_copy_combobox.addItem(item[0]) - self.preferences_data_to_copy_combobox.currentIndexChanged.connect( - self.preferences_data_to_copy_combobox_changed) - vbox_data.addWidget(self.preferences_data_to_copy_combobox) - vbox.addLayout(vbox_data) - - vbox_select = QtGui.QVBoxLayout() - vbox_select.addWidget(QtGui.QLabel('Dataset Selection Mechanism:')) - self.preferences_selection_mechanism_combobox = QtGui.QComboBox() - for item in self.preferences_selection_mechanism: - self.preferences_selection_mechanism_combobox.addItem(item) - self.preferences_selection_mechanism_combobox.currentIndexChanged.connect( - self.preferences_selection_mechanism_combobox_changed) - index = self.preferences_selection_mechanism_combobox.findText(self.preferences['dataset_selection_mechanism'], QtCore.Qt.MatchFixedString) - self.preferences_selection_mechanism_combobox.setCurrentIndex(index) - vbox_select.addWidget(self.preferences_selection_mechanism_combobox) - vbox.addLayout(vbox_select) - - vbox_inital_refinement = QtGui.QVBoxLayout() - vbox_inital_refinement.addWidget(QtGui.QLabel('Initial Refinement Pipeline:')) - self.preferences_initial_refinement_combobox = QtGui.QComboBox() - for item in self.preferences_initial_refinement_pipeline: - self.preferences_initial_refinement_combobox.addItem(item) - self.preferences_initial_refinement_combobox.currentIndexChanged.connect( - self.preferences_initial_refinement_combobox_changed) - index = self.preferences_initial_refinement_combobox.findText(self.preferences['initial_refinement_pipeline'], QtCore.Qt.MatchFixedString) - self.preferences_initial_refinement_combobox.setCurrentIndex(index) - vbox_inital_refinement.addWidget(self.preferences_initial_refinement_combobox) - vbox.addLayout(vbox_inital_refinement) - - vbox_restraints = QtGui.QVBoxLayout() - vbox_restraints.addWidget(QtGui.QLabel('Restraints generation program:')) - self.preferences_restraints_generation_combobox = QtGui.QComboBox() - program_list = [] - - if self.external_software['acedrg']: - program_list.append('acedrg') - self.restraints_program = 'acedrg' - if self.external_software['phenix.elbow']: program_list.append('phenix.elbow') - if self.external_software['grade']: program_list.append('grade') - for item in program_list: - self.preferences_restraints_generation_combobox.addItem(item) - self.preferences_restraints_generation_combobox.currentIndexChanged.connect( - self.preferences_restraints_generation_combobox_changed) - index = self.preferences_restraints_generation_combobox.findText(self.restraints_program, - QtCore.Qt.MatchFixedString) - self.preferences_restraints_generation_combobox.setCurrentIndex(index) - vbox_restraints.addWidget(self.preferences_restraints_generation_combobox) - vbox.addLayout(vbox_restraints) - - hbox = QtGui.QHBoxLayout() - hbox.addWidget(QtGui.QLabel('XCE logfile:')) - self.xce_logfile_label = QtGui.QLabel(self.xce_logfile) - hbox.addWidget(self.xce_logfile_label) - button = QtGui.QPushButton("Change") - button.clicked.connect(self.set_xce_logfile) - hbox.addWidget(button) - vbox.addLayout(hbox) - - settings_hbox_max_queue_jobs = QtGui.QHBoxLayout() - adjust_max_queue_jobs_label = QtGui.QLabel('Max. number of jobs running at once on DLS cluster:') - settings_hbox_max_queue_jobs.addWidget(adjust_max_queue_jobs_label) - adjust_max_queue_jobs = QtGui.QLineEdit() - adjust_max_queue_jobs.setFixedWidth(200) - adjust_max_queue_jobs.setText(str(self.max_queue_jobs)) - adjust_max_queue_jobs.textChanged[str].connect(self.change_max_queue_jobs) - settings_hbox_max_queue_jobs.addWidget(adjust_max_queue_jobs) - vbox.addLayout(settings_hbox_max_queue_jobs) - - settings_hbox_remote_qsub = QtGui.QHBoxLayout() - remote_qsub_label = QtGui.QLabel('remote qsub:') - settings_hbox_remote_qsub.addWidget(remote_qsub_label) - self.remote_qsub_checkbox = QtGui.QCheckBox('use') - #self.remote_qsub_checkbox.toggled.connect(self.run_qsub_remotely) - - settings_hbox_dimple_twin_mode = QtGui.QHBoxLayout() - self.dimple_twin_mode_label_checkbox = QtGui.QCheckBox('run DIMPLE in TWIN mode') - if self.preferences['dimple_twin_mode']: - self.dimple_twin_mode_label_checkbox.setChecked(True) - self.dimple_twin_mode_label_checkbox.toggled.connect(self.dimple_change_twin_mode) - settings_hbox_dimple_twin_mode.addWidget(self.dimple_twin_mode_label_checkbox) - vbox.addLayout(settings_hbox_dimple_twin_mode) - - if self.using_remote_qsub_submission: - self.remote_qsub_checkbox.setChecked(True) - settings_hbox_remote_qsub.addWidget(self.remote_qsub_checkbox) - self.remote_qsub_command = QtGui.QLineEdit() - self.remote_qsub_command.setFixedWidth(550) - self.remote_qsub_command.setText(self.remote_qsub_submission) - settings_hbox_remote_qsub.addWidget(self.remote_qsub_command) - vbox.addLayout(settings_hbox_remote_qsub) - - hbox = QtGui.QHBoxLayout() - hbox.addWidget(QtGui.QLabel('Additional CIF file for non-standard ligand:')) - self.second_cif_file_label = QtGui.QLabel(self.second_cif_file) - hbox.addWidget(self.second_cif_file_label) - button = QtGui.QPushButton("Select") - button.clicked.connect(self.set_second_cif_file) - hbox.addWidget(button) - vbox.addLayout(hbox) - - -# settings_hbox_max_queue_jobs.addWidget(adjust_max_queue_jobs_label) -# adjust_max_queue_jobs = QtGui.QLineEdit() -# adjust_max_queue_jobs.setFixedWidth(200) -# adjust_max_queue_jobs.setText(str(self.max_queue_jobs)) -# adjust_max_queue_jobs.textChanged[str].connect(self.change_max_queue_jobs) -# settings_hbox_max_queue_jobs.addWidget(adjust_max_queue_jobs) -# vbox.addLayout(settings_hbox_max_queue_jobs) -# -# apply_button = QtGui.QPushButton('Apply') -# apply_button.clicked.connect(self.run_qsub_remotely) -# settings_hbox_remote_qsub.addWidget(apply_button) - - - preferencesLayout.addLayout(vbox, 0, 0) - - preferences.exec_(); - -# def set_second_cif_file(self): -# mb = QtGui.QMessageBox() -# mbLayout = mb.layout() -# vbox = QtGui.QVBoxLayout() -# vbox.addWidget(QtGui.QLabel('CIF file to be merged into ligand CIF files:')) -# self.second_cif_file_label = QtGui.QLabel(self.second_cif_file) -# vbox.addWidget(self.second_cif_file_label) -# button = QtGui.QPushButton("Select") -# button.clicked.connect(self.set_second_cif_file) -# vbox.addWidget(button) -# mbLayout.addLayout(vbox, 0, 0) -# mb.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) -# mb.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) -# reply = mb.exec_(); - - - - def dimple_change_twin_mode(self): - if self.preferences['dimple_twin_mode']: - self.update_log.insert('changing preferences: turning off DIMPLE in TWIN mode') - self.preferences['dimple_twin_mode'] = False - else: - self.update_log.insert('changing preferences: changing DIMPLE to TWIN mode') - self.preferences['dimple_twin_mode'] = True - - def run_qsub_remotely(self): - self.remote_qsub_submission = str(self.remote_qsub_command.text()) - print(str(self.remote_qsub_submission)) - if self.remote_qsub_checkbox.isChecked(): - self.update_log.insert('submitting jobs to remote machine with: %s' % self.remote_qsub_submission) - self.external_software['qsub_remote'] = self.remote_qsub_submission - self.using_remote_qsub_submission = True - self.settings['remote_qsub'] = self.remote_qsub_submission - else: - self.update_log.insert('switching off remote job submission') - self.external_software['qsub_remote'] = '' - self.settings['remote_qsub'] = '' - self.using_remote_qsub_submission = False - - def enter_pdb_codes(self): - pdbID_entry = QtGui.QMessageBox() - pdbID_entryLayout = pdbID_entry.layout() - - vbox = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - - grid.addWidget(QtGui.QLabel('Text from PDB email'), 0, 0) - self.pdb_code_entry = QtGui.QTextEdit() - self.pdb_code_entry.setText('') - self.pdb_code_entry.setFixedWidth(500) - grid.addWidget(self.pdb_code_entry, 1, 0, 20, 1) - - frame.setLayout(grid) - vbox.addWidget(frame) - - hbox = QtGui.QHBoxLayout() - button = QtGui.QPushButton('Update Database') - button.clicked.connect(self.update_database_with_pdb_codes) - hbox.addWidget(button) - - vbox.addLayout(hbox) - pdbID_entryLayout.addLayout(vbox, 0, 0) - pdbID_entry.exec_(); - - - def add_label_information(self): - label_entry = QtGui.QMessageBox() - label_entryLayout = label_entry.layout() - - try: - labelInfo = self.db.get_label_info_from_db() - except AttributeError: - self.update_log.warning('please specify DB file first') - return None - - vbox = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - grid.addWidget(QtGui.QLabel('label'), 0, 0) - grid.addWidget(QtGui.QLabel('description'), 0, 1) - - self.remote_qsub_command = QtGui.QLineEdit() - self.remote_qsub_command.setFixedWidth(550) - self.remote_qsub_command.setText(self.remote_qsub_submission) - - self.labelList = [] - for i in range(5): - labelEdit = QtGui.QLineEdit() - descriptionEdit = QtGui.QLineEdit() - grid.addWidget(labelEdit, i + 1, 0) - grid.addWidget(descriptionEdit, i + 1, 1) - try: - labelEdit.setText(labelInfo[i][0]) - descriptionEdit.setText(labelInfo[i][1]) - except IndexError: - labelEdit.setText('') - descriptionEdit.setText('') - labelEdit.setFixedWidth(100) - descriptionEdit.setFixedWidth(500) - self.labelList.append([labelEdit,descriptionEdit]) - frame.setLayout(grid) - vbox.addWidget(frame) - - hbox = QtGui.QHBoxLayout() - button = QtGui.QPushButton('Update Database') - button.clicked.connect(self.update_database_with_labelInfo) - hbox.addWidget(button) - - vbox.addLayout(hbox) - label_entryLayout.addLayout(vbox, 0, 0) - label_entry.exec_(); - - - - - - - - def create_missing_apo_records_in_depositTable(self): - self.db.create_missing_apo_records_for_all_structures_in_depositTable(self.initial_model_directory, - self.xce_logfile) - -# def update_file_information_of_apo_records(self): -# XChemDeposit.update_file_locations_of_apo_structuresin_DB( -# os.path.join(self.database_directory, self.data_source_file), self.initial_model_directory, -# self.xce_logfile) - - def prepare_models_for_deposition_ligand_bound(self,structureType): - - ignore_event_map = False - if structureType == 'ground-state': - ground_state = [ str(self.ground_state_pdb_button_label.text()), - str(self.ground_state_mtz_button_label.text()), - self.panddas_directory ] - else: - ground_state = [] - if self.deposition_bounnd_state_preparation_ignore_event_map.isChecked(): - ignore_event_map = True - -# structureType = "ligand_bound" - - overwrite_existing_mmcif = True - self.work_thread = XChemDeposit.prepare_mmcif_files_for_deposition( - os.path.join(self.database_directory, self.data_source_file), - self.xce_logfile, - overwrite_existing_mmcif, - self.initial_model_directory, - ground_state, - ignore_event_map) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def prepare_models_for_deposition_apo(self): - - structureType = "apo" - - overwrite_existing_mmcif = True - self.work_thread = XChemDeposit.prepare_mmcif_files_for_deposition( - os.path.join(self.database_directory, self.data_source_file), - self.xce_logfile, - overwrite_existing_mmcif, - self.initial_model_directory, - structureType) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def prepare_for_group_deposition_upload_ligand_bound(self): - - self.work_thread = XChemDeposit.prepare_for_group_deposition_upload( - os.path.join(self.database_directory, self.data_source_file), - self.xce_logfile, - self.group_deposit_directory,self.initial_model_directory,'ligand_bound') - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def prepare_for_group_deposition_upload_ground_state(self): - - self.work_thread = XChemDeposit.prepare_for_group_deposition_upload( - os.path.join(self.database_directory, self.data_source_file), - self.xce_logfile, - self.group_deposit_directory,self.initial_model_directory,'ground_state') - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def check_smiles_in_db_and_pdb(self): - - self.work_thread = XChemDeposit.compare_smiles_in_db_with_ligand_in_pdb(self.initial_model_directory, - os.path.join(self.database_directory, - self.data_source_file), - self.xce_logfile) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("show_error_dict"), self.show_error_dict) - self.work_thread.start() - - def deposition_data(self): - - depositData = QtGui.QMessageBox() - depositDataLayout = depositData.layout() - - vbox = QtGui.QVBoxLayout() - - deposit_tab_widget = QtGui.QTabWidget() - deposit_tab_list = ['Contact', - 'General', - 'Authors', - 'Citation', - 'Molecule', - 'Misc', - 'Methods', - 'Software'] - - deposit_tab_dict = {} - for page in deposit_tab_list: - tab = QtGui.QWidget() - vb = QtGui.QVBoxLayout(tab) - deposit_tab_widget.addTab(tab, page) - deposit_tab_dict[page] = [tab, vb] - - ## PI and scientist info - vb = QtGui.QVBoxLayout() - hbox = QtGui.QHBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - grid.addWidget(QtGui.QLabel('Principal Investigator'), 0, 0) - - grid.addWidget(QtGui.QLabel('Salutation'), 1, 0) - self.contact_author_PI_salutation = QtGui.QLineEdit() - self.contact_author_PI_salutation.setText('Dr.') - self.contact_author_PI_salutation.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_salutation, 1, 1) - - grid.addWidget(QtGui.QLabel('First name'), 2, 0) - self.contact_author_PI_first_name = QtGui.QLineEdit() - self.contact_author_PI_first_name.setText('') - self.contact_author_PI_first_name.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_first_name, 2, 1) - - grid.addWidget(QtGui.QLabel('Last name'), 3, 0) - self.contact_author_PI_last_name = QtGui.QLineEdit() - self.contact_author_PI_last_name.setText('') - self.contact_author_PI_last_name.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_last_name, 3, 1) - - grid.addWidget(QtGui.QLabel('Middle name'), 4, 0) - self.contact_author_PI_middle_name = QtGui.QLineEdit() - self.contact_author_PI_middle_name.setText('') - self.contact_author_PI_middle_name.setFixedWidth(200) - self.contact_author_PI_middle_name.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.contact_author_PI_middle_name, 4, 1) - - grid.addWidget(QtGui.QLabel('PI role'), 5, 0) - self.contact_author_PI_role = QtGui.QComboBox() -# PIroles = ['group leader', 'principal investigator/group leader', 'investigator'] - PIroles = ['principal investigator/group leader'] - for item in PIroles: self.contact_author_PI_role.addItem(item) - grid.addWidget(self.contact_author_PI_role, 5, 1) - - grid.addWidget(QtGui.QLabel('Organization type'), 6, 0) - self.contact_author_PI_organization_type = QtGui.QComboBox() - Organizations = ['academic', 'commercial', 'government'] - for item in Organizations: self.contact_author_PI_organization_type.addItem(item) - grid.addWidget(self.contact_author_PI_organization_type, 6, 1) - - grid.addWidget(QtGui.QLabel('Organization Name'), 7, 0) - self.contact_author_PI_organization_name = QtGui.QLineEdit() - self.contact_author_PI_organization_name.setText('') - self.contact_author_PI_organization_name.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_organization_name, 7, 1) - - grid.addWidget(QtGui.QLabel('Email'), 8, 0) - self.contact_author_PI_email = QtGui.QLineEdit() - self.contact_author_PI_email.setText('') - self.contact_author_PI_email.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_email, 8, 1) - - grid.addWidget(QtGui.QLabel('Street'), 9, 0) - self.contact_author_PI_address = QtGui.QLineEdit() - self.contact_author_PI_address.setText('') - self.contact_author_PI_address.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_address, 9, 1) - - grid.addWidget(QtGui.QLabel('City'), 10, 0) - self.contact_author_PI_city = QtGui.QLineEdit() - self.contact_author_PI_city.setText('') - self.contact_author_PI_city.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_city, 10, 1) - - grid.addWidget(QtGui.QLabel('State'), 11, 0) - self.contact_author_PI_State_or_Province = QtGui.QLineEdit() - self.contact_author_PI_State_or_Province.setText('') - self.contact_author_PI_State_or_Province.setFixedWidth(200) - self.contact_author_PI_State_or_Province.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.contact_author_PI_State_or_Province, 11, 1) - - grid.addWidget(QtGui.QLabel('ZIP code'), 12, 0) - self.contact_author_PI_Zip_Code = QtGui.QLineEdit() - self.contact_author_PI_Zip_Code.setText('') - self.contact_author_PI_Zip_Code.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_Zip_Code, 12, 1) - - grid.addWidget(QtGui.QLabel('Country'), 13, 0) - self.contact_author_PI_Country = QtGui.QLineEdit() - self.contact_author_PI_Country.setText('') - self.contact_author_PI_Country.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_Country, 13, 1) - - grid.addWidget(QtGui.QLabel('Phone'), 14, 0) - self.contact_author_PI_phone_number = QtGui.QLineEdit() - self.contact_author_PI_phone_number.setText('') - self.contact_author_PI_phone_number.setFixedWidth(200) - grid.addWidget(self.contact_author_PI_phone_number, 14, 1) - - frame.setLayout(grid) - hbox.addWidget(frame) - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - grid = QtGui.QGridLayout() - grid.addWidget(QtGui.QLabel('Responsible Scientist'), 0, 0) - - grid.addWidget(QtGui.QLabel('Salutation'), 1, 0) - self.contact_author_salutation = QtGui.QLineEdit() - self.contact_author_salutation.setText('Dr.') - self.contact_author_salutation.setFixedWidth(200) - grid.addWidget(self.contact_author_salutation, 1, 1) - - grid.addWidget(QtGui.QLabel('First name'), 2, 0) - self.contact_author_first_name = QtGui.QLineEdit() - self.contact_author_first_name.setText('') - self.contact_author_first_name.setFixedWidth(200) - grid.addWidget(self.contact_author_first_name, 2, 1) - - grid.addWidget(QtGui.QLabel('Last name'), 3, 0) - self.contact_author_last_name = QtGui.QLineEdit() - self.contact_author_last_name.setText('') - self.contact_author_last_name.setFixedWidth(200) - grid.addWidget(self.contact_author_last_name, 3, 1) - - grid.addWidget(QtGui.QLabel('Middle name'), 4, 0) - self.contact_author_middle_name = QtGui.QLineEdit() - self.contact_author_middle_name.setText('') - self.contact_author_middle_name.setFixedWidth(200) - self.contact_author_middle_name.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.contact_author_middle_name, 4, 1) - - grid.addWidget(QtGui.QLabel('Role'), 5, 0) - - self.contact_author_role = QtGui.QComboBox() - ScientistRoles = ['responsible scientist', 'investigator'] - for item in ScientistRoles: self.contact_author_role.addItem(item) - grid.addWidget(self.contact_author_role, 5, 1) - - grid.addWidget(QtGui.QLabel('Organization type'), 6, 0) - - self.contact_author_organization_type = QtGui.QComboBox() - for item in Organizations: self.contact_author_organization_type.addItem(item) - grid.addWidget(self.contact_author_organization_type, 6, 1) - - grid.addWidget(QtGui.QLabel('Organization Name'), 7, 0) - self.contact_author_organization_name = QtGui.QLineEdit() - self.contact_author_organization_name.setText('') - self.contact_author_organization_name.setFixedWidth(200) - grid.addWidget(self.contact_author_organization_name, 7, 1) - - grid.addWidget(QtGui.QLabel('Email'), 8, 0) - self.contact_author_email = QtGui.QLineEdit() - self.contact_author_email.setText('') - self.contact_author_email.setFixedWidth(200) - grid.addWidget(self.contact_author_email, 8, 1) - - grid.addWidget(QtGui.QLabel('Street'), 9, 0) - self.contact_author_address = QtGui.QLineEdit() - self.contact_author_address.setText('') - self.contact_author_address.setFixedWidth(200) - grid.addWidget(self.contact_author_address, 9, 1) - - grid.addWidget(QtGui.QLabel('City'), 10, 0) - self.contact_author_city = QtGui.QLineEdit() - self.contact_author_city.setText('') - self.contact_author_city.setFixedWidth(200) - grid.addWidget(self.contact_author_city, 10, 1) - - grid.addWidget(QtGui.QLabel('State'), 11, 0) - self.contact_author_State_or_Province = QtGui.QLineEdit() - self.contact_author_State_or_Province.setText('') - self.contact_author_State_or_Province.setFixedWidth(200) - self.contact_author_State_or_Province.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.contact_author_State_or_Province, 11, 1) - - grid.addWidget(QtGui.QLabel('ZIP code'), 12, 0) - self.contact_author_Zip_Code = QtGui.QLineEdit() - self.contact_author_Zip_Code.setText('') - self.contact_author_Zip_Code.setFixedWidth(200) - grid.addWidget(self.contact_author_Zip_Code, 12, 1) - - grid.addWidget(QtGui.QLabel('Country'), 13, 0) - self.contact_author_Country = QtGui.QLineEdit() - self.contact_author_Country.setText('') - self.contact_author_Country.setFixedWidth(200) - grid.addWidget(self.contact_author_Country, 13, 1) - - grid.addWidget(QtGui.QLabel('Phone'), 14, 0) - self.contact_author_phone_number = QtGui.QLineEdit() - self.contact_author_phone_number.setText('') - self.contact_author_phone_number.setFixedWidth(200) - grid.addWidget(self.contact_author_phone_number, 14, 1) - - frame.setLayout(grid) - hbox.addWidget(frame) - - vb.addLayout(hbox) - vb.addWidget(QtGui.QLabel(XChemToolTips.deposition_interface_note())) - vb.addStretch(1) - - deposit_tab_dict['Contact'][1].addLayout(vb) - - ## release status - vb = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - grid.addWidget(QtGui.QLabel('Release status'), 0, 0) - - grid.addWidget(QtGui.QLabel('Release Status for sequence'), 4, 0) - - self.Release_status_for_sequence = QtGui.QComboBox() - codeStatus = ['RELEASE NOW', 'HOLD FOR RELEASE'] - for item in codeStatus: self.Release_status_for_sequence.addItem(item) - grid.addWidget(self.Release_status_for_sequence, 4, 1) - - grid.addWidget(QtGui.QLabel('Release Status for coordinates/ SF'), 8, 0) - self.Release_status_for_coordinates = QtGui.QComboBox() - coordStatus = ['RELEASE NOW', 'HOLD FOR PUBLICATION', 'HOLD FOR 4 WEEKS', 'HOLD FOR 6 MONTHS', - 'HOLD FOR 1 YEAR'] - for item in coordStatus: self.Release_status_for_coordinates.addItem(item) - grid.addWidget(self.Release_status_for_coordinates, 8, 1) - - frame.setLayout(grid) - vb.addWidget(frame) - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - grid.addWidget(QtGui.QLabel('Title & Details'), 0, 0) - note = ( - 'Note: supported wildcards: $ProteinName,$CompoundName; e.g. "Crystal Structure of human JMJD2D in complex with N2317a"') - grid.addWidget(QtGui.QLabel(note), 1, 0) - - grid.addWidget(QtGui.QLabel('Group deposition title'), 2, 0) - self.group_deposition_title = QtGui.QLineEdit() - self.group_deposition_title.setText('PanDDA analysis group deposition') - self.group_deposition_title.setFixedWidth(600) - # self.group_deposition_title.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.group_deposition_title, 2, 1) - - grid.addWidget(QtGui.QLabel('Description'), 3, 0) - self.group_description = QtGui.QLineEdit() - self.group_description.setText( - 'XDomainX of XOrganismX $ProteinName screened against the XXX Fragment Library by X-ray Crystallography at the XChem facility of Diamond Light Source beamline I04-1') - self.group_description.setFixedWidth(600) - grid.addWidget(self.group_description, 3, 1) - - grid.addWidget(QtGui.QLabel('Structure Title (ligand bound)'), 4, 0) - self.structure_title = QtGui.QLineEdit() - self.structure_title.setText('Crystal Structure of $ProteinName in complex with $CompoundName') - self.structure_title.setFixedWidth(600) - grid.addWidget(self.structure_title, 4, 1) - - note = ('\n\nApo Structure:\nonly use if you want to deposit PanDDA models!') - grid.addWidget(QtGui.QLabel(note), 6, 0) - - grid.addWidget(QtGui.QLabel('Structure Title (apo)'), 7, 0) - self.structure_title_apo = QtGui.QLineEdit() - self.structure_title_apo.setText( - 'PanDDA analysis group deposition of ground-state model of $ProteinName') - self.structure_title_apo.setFixedWidth(600) - grid.addWidget(self.structure_title_apo, 7, 1) - - frame.setLayout(grid) - vb.addWidget(frame) - - vb.addStretch(1) - - deposit_tab_dict['General'][1].addLayout(vb) - - ## authors - vb = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - grid.addWidget(QtGui.QLabel('Deposition authors (e.g. Surname, F.M.)'), 0, 0) - - self.structure_author_name_List = [] - - for column in range(0, 2): - for row in range(1, 15): - structure_author_name = QtGui.QLineEdit() - structure_author_name.setText('') - structure_author_name.setFixedWidth(300) - grid.addWidget(structure_author_name, row, column) - self.structure_author_name_List.append(structure_author_name) - - frame.setLayout(grid) - vb.addWidget(frame) - - vb.addStretch(1) - - deposit_tab_dict['Authors'][1].addLayout(vb) - - ## primary citation - vb = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - grid.addWidget(QtGui.QLabel('Primary Citation'), 0, 0) - - grid.addWidget(QtGui.QLabel('ID'), 1, 0) - self.primary_citation_id = QtGui.QLineEdit() - self.primary_citation_id.setText('primary') - self.primary_citation_id.setFixedWidth(500) - grid.addWidget(self.primary_citation_id, 1, 1) - - grid.addWidget(QtGui.QLabel('Journal'), 2, 0) - self.primary_citation_journal_abbrev = QtGui.QLineEdit() - self.primary_citation_journal_abbrev.setText('To be published') - self.primary_citation_journal_abbrev.setFixedWidth(500) - grid.addWidget(self.primary_citation_journal_abbrev, 2, 1) - - grid.addWidget(QtGui.QLabel('Title'), 3, 0) - self.primary_citation_title = QtGui.QLineEdit() - self.primary_citation_title.setText('') - self.primary_citation_title.setFixedWidth(500) - self.primary_citation_title.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.primary_citation_title, 3, 1) - - grid.addWidget(QtGui.QLabel('Year'), 4, 0) - self.primary_citation_year = QtGui.QLineEdit() - self.primary_citation_year.setText('') - self.primary_citation_year.setFixedWidth(500) - self.primary_citation_year.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.primary_citation_year, 4, 1) - - grid.addWidget(QtGui.QLabel('Volume'), 5, 0) - self.primary_citation_journal_volume = QtGui.QLineEdit() - self.primary_citation_journal_volume.setText('') - self.primary_citation_journal_volume.setFixedWidth(500) - self.primary_citation_journal_volume.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.primary_citation_journal_volume, 5, 1) - - grid.addWidget(QtGui.QLabel('Page, first'), 6, 0) - self.primary_citation_page_first = QtGui.QLineEdit() - self.primary_citation_page_first.setText('') - self.primary_citation_page_first.setFixedWidth(500) - self.primary_citation_page_first.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.primary_citation_page_first, 6, 1) - - grid.addWidget(QtGui.QLabel('Page, last'), 7, 0) - self.primary_citation_page_last = QtGui.QLineEdit() - self.primary_citation_page_last.setText('') - self.primary_citation_page_last.setFixedWidth(500) - self.primary_citation_page_last.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.primary_citation_page_last, 7, 1) - - frame.setLayout(grid) - vb.addWidget(frame) - - ## citation authors - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - self.set_primary_citation_authors = QtGui.QCheckBox('same as deposition authors') - self.layout_funcs.add_checkbox(self, self.set_primary_citation_authors, - 'xce_object.set_primary_citation_as_structure_authors') - grid.addWidget(self.set_primary_citation_authors, 0, 0) - - self.primary_citation_author_name_List = [] - - for column in range(0, 2): - for row in range(1, 15): - primary_citation_author_name = QtGui.QLineEdit() - primary_citation_author_name.setText('') - primary_citation_author_name.setFixedWidth(300) - grid.addWidget(primary_citation_author_name, row, column) - self.primary_citation_author_name_List.append(primary_citation_author_name) - - frame.setLayout(grid) - vb.addWidget(frame) - - vb.addStretch(1) - - deposit_tab_dict['Citation'][1].addLayout(vb) - - ## molecule info - vb = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - - grid.addWidget(QtGui.QLabel('Entity 1'), 1, 0) - - grid.addWidget(QtGui.QLabel('Molecule Name'), 2, 0) - self.molecule_name = QtGui.QLineEdit() - self.molecule_name.setText('') - self.molecule_name.setFixedWidth(300) - self.molecule_name.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.molecule_name, 2, 1) - grid.addWidget(QtGui.QLabel('(e.g. RNA Hammerhead Ribozyme)'), 2, 2) - - grid.addWidget(QtGui.QLabel('Fragment Name'), 3, 0) - self.fragment_name_one = QtGui.QLineEdit() - self.fragment_name_one.setText('') - self.fragment_name_one.setFixedWidth(300) - self.fragment_name_one.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.fragment_name_one, 3, 1) - grid.addWidget(QtGui.QLabel('(e.g. ligand binding domain, hairpin)'), 3, 2) - - grid.addWidget(QtGui.QLabel('Specific Mutation'), 4, 0) - self.fragment_name_one_specific_mutation = QtGui.QLineEdit() - self.fragment_name_one_specific_mutation.setText('') - self.fragment_name_one_specific_mutation.setFixedWidth(300) - self.fragment_name_one_specific_mutation.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.fragment_name_one_specific_mutation, 4, 1) - grid.addWidget(QtGui.QLabel('(e.g. C280S)'), 4, 2) - - grid.addWidget(QtGui.QLabel('Enzyme Comission Number'), 5, 0) - self.fragment_name_one_enzyme_comission_number = QtGui.QLineEdit() - self.fragment_name_one_enzyme_comission_number.setText('') - self.fragment_name_one_enzyme_comission_number.setFixedWidth(300) - self.fragment_name_one_enzyme_comission_number.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.fragment_name_one_enzyme_comission_number, 5, 1) - grid.addWidget(QtGui.QLabel('(if known: e.g. 2.7.7.7)'), 5, 2) - - grid.addWidget(QtGui.QLabel('Genetically Manipulated Source'), 6, 0) - - grid.addWidget(QtGui.QLabel('Source organism scientific name'), 7, 0) - - self.Source_organism_scientific_name = QtGui.QComboBox() - taxonomy_dict = XChemMain.NCBI_taxonomy_ID() - for item in taxonomy_dict: - self.Source_organism_scientific_name.addItem(taxonomy_dict[item]) - grid.addWidget(self.Source_organism_scientific_name, 7, 1) - - grid.addWidget(QtGui.QLabel('Source organism gene'), 8, 0) - self.Source_organism_gene = QtGui.QLineEdit() - self.Source_organism_gene.setText('') - self.Source_organism_gene.setFixedWidth(300) - grid.addWidget(self.Source_organism_gene, 8, 1) - grid.addWidget(QtGui.QLabel('(e.g. RPOD, ALKA...)'), 8, 2) - - grid.addWidget(QtGui.QLabel('Source organism strain'), 9, 0) - self.Source_organism_strain = QtGui.QLineEdit() - self.Source_organism_strain.setText('') - self.Source_organism_strain.setFixedWidth(300) - self.Source_organism_strain.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Source_organism_strain, 9, 1) - grid.addWidget(QtGui.QLabel('(e.g. BH10 ISOLATE, K-12...)'), 9, 2) - - grid.addWidget(QtGui.QLabel('Expression system scientific name'), 10, 0) - - self.Expression_system_scientific_name = QtGui.QComboBox() - for item in taxonomy_dict: - self.Expression_system_scientific_name.addItem(taxonomy_dict[item]) - grid.addWidget(self.Expression_system_scientific_name, 10, 1) - - grid.addWidget(QtGui.QLabel('Expression system strain'), 11, 0) - self.Expression_system_strain = QtGui.QLineEdit() - self.Expression_system_strain.setText('') - self.Expression_system_strain.setFixedWidth(300) - self.Expression_system_strain.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Expression_system_strain, 11, 1) - grid.addWidget(QtGui.QLabel('(e.g. BL21(DE3))'), 11, 2) - - grid.addWidget(QtGui.QLabel('Expression system vector type'), 12, 0) - self.Expression_system_vector_type = QtGui.QLineEdit() - self.Expression_system_vector_type.setText('') - self.Expression_system_vector_type.setFixedWidth(300) - self.Expression_system_vector_type.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Expression_system_vector_type, 12, 1) - grid.addWidget(QtGui.QLabel('(e.g. plasmid)'), 12, 2) - - grid.addWidget(QtGui.QLabel('Expression_system_plasmid_name'), 13, 0) - self.Expression_system_plasmid_name = QtGui.QLineEdit() - self.Expression_system_plasmid_name.setText('') - self.Expression_system_plasmid_name.setFixedWidth(300) - self.Expression_system_plasmid_name.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Expression_system_plasmid_name, 13, 1) - grid.addWidget(QtGui.QLabel('(e.g. pET26)'), 13, 2) - - grid.addWidget(QtGui.QLabel('Manipulated_source_details'), 14, 0) - self.Manipulated_source_details = QtGui.QLineEdit() - self.Manipulated_source_details.setText('') - self.Manipulated_source_details.setFixedWidth(300) - self.Manipulated_source_details.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Manipulated_source_details, 14, 1) - grid.addWidget(QtGui.QLabel('(any other relevant information)'), 14, 2) - - grid.addWidget(QtGui.QLabel('Chains'), 15, 0) - self.molecule_chain_one = QtGui.QLineEdit() - self.molecule_chain_one.setText('') - self.molecule_chain_one.setFixedWidth(300) - grid.addWidget(self.molecule_chain_one, 15, 1) - grid.addWidget(QtGui.QLabel('(e.g. A or A,B)'), 15, 2) - - frame.setLayout(grid) - vb.addWidget(frame) - - ### entity 2 - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - - grid.addWidget(QtGui.QLabel('Entity 2 (IMPORTANT: only fill in if you are working with a protein-protein complex!)'), 1, 0) - - grid.addWidget(QtGui.QLabel('Molecule Name'), 2, 0) - self.molecule_name_two = QtGui.QLineEdit() - self.molecule_name_two.setText('') - self.molecule_name_two.setFixedWidth(300) - self.molecule_name_two.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.molecule_name_two, 2, 1) - grid.addWidget(QtGui.QLabel('(e.g. RNA Hammerhead Ribozyme)'), 2, 2) - - grid.addWidget(QtGui.QLabel('Fragment Name'), 3, 0) - self.fragment_name_two = QtGui.QLineEdit() - self.fragment_name_two.setText('') - self.fragment_name_two.setFixedWidth(300) - self.fragment_name_two.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.fragment_name_two, 3, 1) - grid.addWidget(QtGui.QLabel('(e.g. ligand binding domain, hairpin)'), 3, 2) - - grid.addWidget(QtGui.QLabel('Specific Mutation'), 4, 0) - self.fragment_name_two_specific_mutation = QtGui.QLineEdit() - self.fragment_name_two_specific_mutation.setText('') - self.fragment_name_two_specific_mutation.setFixedWidth(300) - self.fragment_name_two_specific_mutation.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.fragment_name_two_specific_mutation, 4, 1) - grid.addWidget(QtGui.QLabel('(e.g. C280S)'), 4, 2) - - grid.addWidget(QtGui.QLabel('Enzyme Comission Number'), 5, 0) - self.fragment_name_two_enzyme_comission_number = QtGui.QLineEdit() - self.fragment_name_two_enzyme_comission_number.setText('') - self.fragment_name_two_enzyme_comission_number.setFixedWidth(300) - self.fragment_name_two_enzyme_comission_number.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.fragment_name_two_enzyme_comission_number, 5, 1) - grid.addWidget(QtGui.QLabel('(if known: e.g. 2.7.7.7)'), 5, 2) - - grid.addWidget(QtGui.QLabel('Genetically Manipulated Source'), 6, 0) - - grid.addWidget(QtGui.QLabel('Source organism scientific name'), 7, 0) - - self.Source_organism_scientific_name_two = QtGui.QComboBox() - taxonomy_dict = XChemMain.NCBI_taxonomy_ID() - for item in taxonomy_dict: - self.Source_organism_scientific_name_two.addItem(taxonomy_dict[item]) - grid.addWidget(self.Source_organism_scientific_name_two, 7, 1) - - grid.addWidget(QtGui.QLabel('Source organism gene'), 8, 0) - self.Source_organism_gene_two = QtGui.QLineEdit() - self.Source_organism_gene_two.setText('') - self.Source_organism_gene_two.setFixedWidth(300) - grid.addWidget(self.Source_organism_gene_two, 8, 1) - grid.addWidget(QtGui.QLabel('(e.g. RPOD, ALKA...)'), 8, 2) - - grid.addWidget(QtGui.QLabel('Source organism strain'), 9, 0) - self.Source_organism_strain_two = QtGui.QLineEdit() - self.Source_organism_strain_two.setText('') - self.Source_organism_strain_two.setFixedWidth(300) - self.Source_organism_strain_two.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Source_organism_strain_two, 9, 1) - grid.addWidget(QtGui.QLabel('(e.g. BH10 ISOLATE, K-12...)'), 9, 2) - - grid.addWidget(QtGui.QLabel('Expression system scientific name'), 10, 0) - - self.Expression_system_scientific_name_two = QtGui.QComboBox() - for item in taxonomy_dict: - self.Expression_system_scientific_name_two.addItem(taxonomy_dict[item]) - grid.addWidget(self.Expression_system_scientific_name_two, 10, 1) - - grid.addWidget(QtGui.QLabel('Expression system strain'), 11, 0) - self.Expression_system_strain_two = QtGui.QLineEdit() - self.Expression_system_strain_two.setText('') - self.Expression_system_strain_two.setFixedWidth(300) - self.Expression_system_strain_two.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Expression_system_strain_two, 11, 1) - grid.addWidget(QtGui.QLabel('(e.g. BL21(DE3))'), 11, 2) - - grid.addWidget(QtGui.QLabel('Expression system vector type'), 12, 0) - self.Expression_system_vector_type_two = QtGui.QLineEdit() - self.Expression_system_vector_type_two.setText('') - self.Expression_system_vector_type_two.setFixedWidth(300) - self.Expression_system_vector_type_two.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Expression_system_vector_type_two, 12, 1) - grid.addWidget(QtGui.QLabel('(e.g. plasmid)'), 12, 2) - - grid.addWidget(QtGui.QLabel('Expression_system_plasmid_name'), 13, 0) - self.Expression_system_plasmid_name_two = QtGui.QLineEdit() - self.Expression_system_plasmid_name_two.setText('') - self.Expression_system_plasmid_name_two.setFixedWidth(300) - self.Expression_system_plasmid_name_two.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Expression_system_plasmid_name_two, 13, 1) - grid.addWidget(QtGui.QLabel('(e.g. pET26)'), 13, 2) - - grid.addWidget(QtGui.QLabel('Manipulated_source_details'), 14, 0) - self.Manipulated_source_details_two = QtGui.QLineEdit() - self.Manipulated_source_details_two.setText('') - self.Manipulated_source_details_two.setFixedWidth(300) - self.Manipulated_source_details_two.setStyleSheet("background-color: rgb(192, 192, 192);") - grid.addWidget(self.Manipulated_source_details_two, 14, 1) - grid.addWidget(QtGui.QLabel('(any other relevant information)'), 14, 2) - - grid.addWidget(QtGui.QLabel('Chains'), 15, 0) - self.molecule_chain_two = QtGui.QLineEdit() - self.molecule_chain_two.setText('') - self.molecule_chain_two.setFixedWidth(300) - grid.addWidget(self.molecule_chain_two, 15, 1) - grid.addWidget(QtGui.QLabel('(e.g. A or A,B)'), 15, 2) - - frame.setLayout(grid) - - vb.addWidget(frame) - - ### entity 2 --- END - - - - - vb.addStretch(1) - - deposit_tab_dict['Molecule'][1].addLayout(vb) - - ## misc - vb = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - - grid.addWidget(QtGui.QLabel('Keywords'), 1, 0) - self.structure_keywords = QtGui.QLineEdit() - self.structure_keywords.setText('SGC - Diamond I04-1 fragment screening, PanDDA, XChemExplorer') - self.structure_keywords.setFixedWidth(300) - grid.addWidget(self.structure_keywords, 1, 1) - grid.addWidget(QtGui.QLabel('(e.g. beta barrel, protein-DNA complex)'), 1, 2) - - grid.addWidget(QtGui.QLabel('Biological Assembly'), 2, 0) - self.biological_assembly_chain_number = QtGui.QLineEdit() - self.biological_assembly_chain_number.setText('') - self.biological_assembly_chain_number.setFixedWidth(300) - grid.addWidget(self.biological_assembly_chain_number, 2, 1) - grid.addWidget(QtGui.QLabel('(e.g. 1 for monomer, 2 for dimer ..)'), 2, 2) - - grid.addWidget(QtGui.QLabel('Sequence UNIPROT ID'), 3, 0) - self.molecule_one_letter_sequence_uniprot_id = QtGui.QLineEdit() - self.molecule_one_letter_sequence_uniprot_id.setText('') - self.molecule_one_letter_sequence_uniprot_id.setFixedWidth(300) - grid.addWidget(self.molecule_one_letter_sequence_uniprot_id, 3, 1) - grid.addWidget(QtGui.QLabel('(e.g. Q6B0I6)'), 3, 2) - - grid.addWidget(QtGui.QLabel('Sequence'), 4, 0) - self.molecule_one_letter_sequence = QtGui.QTextEdit() - self.molecule_one_letter_sequence.setText('') - self.molecule_one_letter_sequence.setFixedWidth(300) - grid.addWidget(self.molecule_one_letter_sequence, 4, 1, 7, 2) - - grid.addWidget(QtGui.QLabel('Sequence information for entity 2 (Important: only fill in if you have a protein-protein complex'), 8, 0) - - grid.addWidget(QtGui.QLabel('Sequence UNIPROT ID (Entity 2)'), 9, 0) - self.molecule_one_letter_sequence_uniprot_id_two = QtGui.QLineEdit() - self.molecule_one_letter_sequence_uniprot_id_two.setText('') - self.molecule_one_letter_sequence_uniprot_id_two.setFixedWidth(300) - grid.addWidget(self.molecule_one_letter_sequence_uniprot_id_two, 9, 1) - grid.addWidget(QtGui.QLabel('(e.g. Q6B0I6)'), 9, 2) - - grid.addWidget(QtGui.QLabel('Sequence (Entity 2)'), 10, 0) - self.molecule_one_letter_sequence_two = QtGui.QTextEdit() - self.molecule_one_letter_sequence_two.setText('') - self.molecule_one_letter_sequence_two.setFixedWidth(300) - grid.addWidget(self.molecule_one_letter_sequence_two, 10, 1, 13, 2) - - - grid.addWidget(QtGui.QLabel('Structural Genomic (optional)'), 14, 0) - - grid.addWidget(QtGui.QLabel('Project Name'), 15, 0) - self.SG_project_name = QtGui.QLineEdit() - self.SG_project_name.setText('') - self.SG_project_name.setFixedWidth(300) - grid.addWidget(self.SG_project_name, 15, 1) - grid.addWidget(QtGui.QLabel('(e.g. SGC, Structural Genomics Consortium)'), 15, 2) - - grid.addWidget(QtGui.QLabel('Full Name'), 16, 0) - self.full_name_of_SG_center = QtGui.QLineEdit() - self.full_name_of_SG_center.setText('') - self.full_name_of_SG_center.setFixedWidth(300) - grid.addWidget(self.full_name_of_SG_center, 16, 1) - grid.addWidget(QtGui.QLabel('(e.g. Structural Genomics Consortium)'), 16, 2) - - frame.setLayout(grid) - vb.addWidget(frame) - - vb.addStretch(1) - - deposit_tab_dict['Misc'][1].addLayout(vb) - - ## methods - vb = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - - grid.addWidget(QtGui.QLabel('Crystallization'), 1, 0) - - grid.addWidget(QtGui.QLabel('Method'), 2, 0) - - self.crystallization_method = QtGui.QComboBox() - for item in XChemMain.crystal_growth_methods(): self.crystallization_method.addItem(item) - grid.addWidget(self.crystallization_method, 2, 1) - - grid.addWidget(QtGui.QLabel('pH'), 3, 0) - self.crystallization_pH = QtGui.QLineEdit() - self.crystallization_pH.setText('') - self.crystallization_pH.setFixedWidth(300) - grid.addWidget(self.crystallization_pH, 3, 1) - grid.addWidget(QtGui.QLabel('(e.g. 7.5 ...)'), 3, 2) - - grid.addWidget(QtGui.QLabel('Temperature'), 4, 0) - self.crystallization_temperature = QtGui.QLineEdit() - self.crystallization_temperature.setText('') - self.crystallization_temperature.setFixedWidth(300) - grid.addWidget(self.crystallization_temperature, 4, 1) - grid.addWidget(QtGui.QLabel('(e.g. 298) (in Kelvin)'), 4, 2) - - grid.addWidget(QtGui.QLabel('Condition'), 5, 0) - self.crystallization_details = QtGui.QLineEdit() - self.crystallization_details.setText('') - self.crystallization_details.setFixedWidth(300) - grid.addWidget(self.crystallization_details, 5, 1) - grid.addWidget(QtGui.QLabel('(e.g. PEG 4000, NaCl etc.)'), 5, 2) - - grid.addWidget(QtGui.QLabel('Diffraction Experiment'), 6, 0) - note = ('Note: this information will only be used if it is\n' - 'not already available in the mainTable!\n' - 'Ignore if data were collected at DLS') - grid.addWidget(QtGui.QLabel(note), 7, 0) - - grid.addWidget(QtGui.QLabel('Source'), 8, 0) - - self.radiation_source = QtGui.QComboBox() - for item in XChemMain.radiationSource(): self.radiation_source.addItem(item) - grid.addWidget(self.radiation_source, 8, 1) - - grid.addWidget(QtGui.QLabel('Source Type'), 9, 0) - - self.radiation_source_type = QtGui.QComboBox() - for item in XChemMain.wwBeamlines(): self.radiation_source_type.addItem(item) - grid.addWidget(self.radiation_source_type, 9, 1) - - grid.addWidget(QtGui.QLabel('Wavelength'), 10, 0) - self.radiation_wavelengths = QtGui.QLineEdit() - self.radiation_wavelengths.setText('') - self.radiation_wavelengths.setFixedWidth(300) - grid.addWidget(self.radiation_wavelengths, 10, 1) - grid.addWidget(QtGui.QLabel('(e.g. 1.502)'), 10, 2) - - grid.addWidget(QtGui.QLabel('Detector'), 11, 0) - - self.radiation_detector = QtGui.QComboBox() - for item in XChemMain.detector(): self.radiation_detector.addItem(item) - grid.addWidget(self.radiation_detector, 11, 1) - - grid.addWidget(QtGui.QLabel('Detector Type'), 12, 0) - - self.radiation_detector_type = QtGui.QComboBox() - for item in XChemMain.detectorType(): self.radiation_detector_type.addItem(item) - grid.addWidget(self.radiation_detector_type, 12, 1) - - grid.addWidget(QtGui.QLabel('Date'), 13, 0) - self.data_collection_date = QtGui.QLineEdit() - self.data_collection_date.setText('') - self.data_collection_date.setFixedWidth(300) - grid.addWidget(self.data_collection_date, 13, 1) - grid.addWidget(QtGui.QLabel('(e.g. 2004-01-07)'), 13, 2) - - grid.addWidget(QtGui.QLabel('Temperature'), 14, 0) - self.data_collection_temperature = QtGui.QLineEdit() - self.data_collection_temperature.setText('') - self.data_collection_temperature.setFixedWidth(300) - grid.addWidget(self.data_collection_temperature, 14, 1) - grid.addWidget(QtGui.QLabel('(e.g. 100) (in Kelvin)'), 14, 2) - - grid.addWidget(QtGui.QLabel('Protocol'), 15, 0) - self.data_collection_protocol = QtGui.QLineEdit() - self.data_collection_protocol.setText('SINGLE WAVELENGTH') - self.data_collection_protocol.setFixedWidth(300) - grid.addWidget(self.data_collection_protocol, 15, 1) - grid.addWidget(QtGui.QLabel('(e.g. SINGLE WAVELENGTH, MAD, ...)'), 15, 2) - - frame.setLayout(grid) - vb.addWidget(frame) - - vb.addStretch(1) - - deposit_tab_dict['Methods'][1].addLayout(vb) - - ## software - vb = QtGui.QVBoxLayout() - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - - grid = QtGui.QGridLayout() - - grid.addWidget(QtGui.QLabel('PDB starting model'), 1, 0) - self.pdbx_starting_model = QtGui.QLineEdit() - self.pdbx_starting_model.setText('') - self.pdbx_starting_model.setFixedWidth(300) - grid.addWidget(self.pdbx_starting_model, 1, 1) - grid.addWidget(QtGui.QLabel('(e.g. 7.5 ...)'), 1, 2) - - grid.addWidget(QtGui.QLabel('Data reduction'), 2, 0) - self.data_integration_software = QtGui.QComboBox() - for item in XChemMain.data_integration_software(): self.data_integration_software.addItem(item) - grid.addWidget(self.data_integration_software, 2, 1) - - grid.addWidget(QtGui.QLabel('Phasing'), 3, 0) - self.phasing_software = QtGui.QComboBox() - for item in XChemMain.phasing_software(): self.phasing_software.addItem(item) - grid.addWidget(self.phasing_software, 3, 1) - - frame.setLayout(grid) - vb.addWidget(frame) - vb.addStretch(1) - - deposit_tab_dict['Software'][1].addLayout(vb) - - vbox.addWidget(deposit_tab_widget) - - hbox = QtGui.QHBoxLayout() - button = QtGui.QPushButton('Load\nFile') - button.clicked.connect(self.load_deposit_config_file) - hbox.addWidget(button) - button = QtGui.QPushButton('Save\nFile') - button.clicked.connect(self.save_deposit_config_file) - hbox.addWidget(button) - button = QtGui.QPushButton('Load from\nDatabase') - button.clicked.connect(self.load_deposit_from_database) - button.setEnabled(False) - hbox.addWidget(button) - button = QtGui.QPushButton('Save to\nDatabase') - button.clicked.connect(self.save_deposit_to_database) - hbox.addWidget(button) - - vbox.addLayout(hbox) - depositDataLayout.addLayout(vbox, 0, 0) - - depositData.exec_() - - def save_deposit_config_file(self): - self.update_deposit_dict() - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'Save file', self.current_directory)) - # make sure that the file always has .deposit extension - if str(file_name).rfind('.') != -1: - file_name = file_name[:file_name.rfind('.')] + '.deposit' - else: - file_name = file_name + '.deposit' - pickle.dump(self.deposit_dict, open(file_name, 'wb')) - - def update_database_with_pdb_codes(self): - self.work_thread = XChemDeposit.import_PDB_IDs(str(self.pdb_code_entry.toPlainText()), - os.path.join(self.database_directory, self.data_source_file), - self.xce_logfile) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def update_database_with_labelInfo(self): - for n,l in enumerate(self.labelList): - label = str(l[0].text()) - description = str(l[1].text()) - print "update labelTable set Label='%s',Description='%s' where ID=%s" %(label,description,str(n+1)) - self.db.execute_statement("update labelTable set Label='%s',Description='%s' where ID=%s" %(label,description,str(n+1))) - print label,description - - def load_deposit_config_file(self): - file_name_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Open file', self.current_directory, - '*.deposit') - file_name = tuple(file_name_temp)[0] - self.deposit_dict = pickle.load(open(file_name, "rb")) - print self.deposit_dict - self.update_deposit_input() - - def load_deposit_from_database(self): - print('hallo') - - def save_deposit_to_database(self): - self.update_deposit_dict() - msgBox = QtGui.QMessageBox() - msgBox.setText( - "*** WARNING ***\nAre you sure you want to update the database?\nThis will overwrite previous entries!") - msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - self.work_thread = XChemDeposit.update_depositTable(self.deposit_dict, - os.path.join(self.database_directory, - self.data_source_file), - self.xce_logfile) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def update_deposit_input(self): - try: - self.contact_author_PI_salutation.setText(self.deposit_dict['contact_author_PI_salutation']) - self.contact_author_PI_first_name.setText(self.deposit_dict['contact_author_PI_first_name']) - self.contact_author_PI_last_name.setText(self.deposit_dict['contact_author_PI_last_name']) - self.contact_author_PI_middle_name.setText(self.deposit_dict['contact_author_PI_middle_name']) - index = self.contact_author_PI_role.findText(self.deposit_dict['contact_author_PI_role'], - QtCore.Qt.MatchFixedString) - self.contact_author_PI_role.setCurrentIndex(index) - index = self.contact_author_PI_organization_type.findText( - self.deposit_dict['contact_author_PI_organization_type'], QtCore.Qt.MatchFixedString) - self.contact_author_PI_organization_type.setCurrentIndex(index) - self.contact_author_PI_organization_name.setText(self.deposit_dict['contact_author_PI_organization_name']) - self.contact_author_PI_email.setText(self.deposit_dict['contact_author_PI_email']) - self.contact_author_PI_address.setText(self.deposit_dict['contact_author_PI_address']) - self.contact_author_PI_city.setText(self.deposit_dict['contact_author_PI_city']) - self.contact_author_PI_State_or_Province.setText(self.deposit_dict['contact_author_PI_State_or_Province']) - self.contact_author_PI_Zip_Code.setText(self.deposit_dict['contact_author_PI_Zip_Code']) - self.contact_author_PI_Country.setText(self.deposit_dict['contact_author_PI_Country']) - self.contact_author_PI_phone_number.setText(self.deposit_dict['contact_author_PI_phone_number']) - - self.contact_author_salutation.setText(self.deposit_dict['contact_author_salutation']) - self.contact_author_first_name.setText(self.deposit_dict['contact_author_first_name']) - self.contact_author_last_name.setText(self.deposit_dict['contact_author_last_name']) - self.contact_author_middle_name.setText(self.deposit_dict['contact_author_middle_name']) - index = self.contact_author_role.findText(self.deposit_dict['contact_author_role'], - QtCore.Qt.MatchFixedString) - self.contact_author_role.setCurrentIndex(index) - index = self.contact_author_organization_type.findText( - self.deposit_dict['contact_author_organization_type'], QtCore.Qt.MatchFixedString) - self.contact_author_organization_type.setCurrentIndex(index) - self.contact_author_organization_name.setText(self.deposit_dict['contact_author_organization_name']) - self.contact_author_email.setText(self.deposit_dict['contact_author_email']) - self.contact_author_address.setText(self.deposit_dict['contact_author_address']) - self.contact_author_city.setText(self.deposit_dict['contact_author_city']) - self.contact_author_State_or_Province.setText(self.deposit_dict['contact_author_State_or_Province']) - self.contact_author_Zip_Code.setText(self.deposit_dict['contact_author_Zip_Code']) - self.contact_author_Country.setText(self.deposit_dict['contact_author_Country']) - self.contact_author_phone_number.setText(self.deposit_dict['contact_author_phone_number']) - index = self.Release_status_for_coordinates.findText(self.deposit_dict['Release_status_for_coordinates'], - QtCore.Qt.MatchFixedString) - self.Release_status_for_coordinates.setCurrentIndex(index) - index = self.Release_status_for_sequence.findText(self.deposit_dict['Release_status_for_sequence'], - QtCore.Qt.MatchFixedString) - self.Release_status_for_sequence.setCurrentIndex(index) - - self.group_deposition_title.setText(self.deposit_dict['group_deposition_title']) - self.group_description.setText(self.deposit_dict['group_description']) - - self.structure_title.setText(self.deposit_dict['structure_title']) - self.structure_title_apo.setText(self.deposit_dict['structure_title_apo']) - - for n, name in enumerate(self.deposit_dict['structure_author_name'].split(';')): - self.structure_author_name_List[n].setText(name) - - self.primary_citation_id.setText(self.deposit_dict['primary_citation_id']) - self.primary_citation_journal_abbrev.setText(self.deposit_dict['primary_citation_journal_abbrev']) - self.primary_citation_title.setText(self.deposit_dict['primary_citation_title']) - self.primary_citation_year.setText(self.deposit_dict['primary_citation_year']) - self.primary_citation_journal_volume.setText(self.deposit_dict['primary_citation_journal_volume']) - self.primary_citation_page_first.setText(self.deposit_dict['primary_citation_page_first']) - self.primary_citation_page_last.setText(self.deposit_dict['primary_citation_page_last']) - - for n, name in enumerate(self.deposit_dict['primary_citation_author_name'].split(';')): - self.primary_citation_author_name_List[n].setText(name) - - ### entity 1 - - self.molecule_name.setText(self.deposit_dict['molecule_name']) - self.fragment_name_one_specific_mutation.setText(self.deposit_dict['fragment_name_one_specific_mutation']) - index = self.Source_organism_scientific_name.findText(self.deposit_dict['Source_organism_scientific_name'], - QtCore.Qt.MatchFixedString) - self.Source_organism_scientific_name.setCurrentIndex(index) - - self.Source_organism_gene.setText(self.deposit_dict['Source_organism_gene']) - self.Source_organism_strain.setText(self.deposit_dict['Source_organism_strain']) - index = self.Expression_system_scientific_name.findText( - self.deposit_dict['Expression_system_scientific_name'], QtCore.Qt.MatchFixedString) - self.Expression_system_scientific_name.setCurrentIndex(index) - - self.Expression_system_strain.setText(self.deposit_dict['Expression_system_strain']) - self.Expression_system_vector_type.setText(self.deposit_dict['Expression_system_vector_type']) - self.Expression_system_plasmid_name.setText(self.deposit_dict['Expression_system_plasmid_name']) - self.Manipulated_source_details.setText(self.deposit_dict['Manipulated_source_details']) - -# try: - self.molecule_chain_one.setText(self.deposit_dict['molecule_chain_one']) - ### entity 2 - self.molecule_name_two.setText(self.deposit_dict['molecule_name_two']) - self.fragment_name_two_specific_mutation.setText(self.deposit_dict['fragment_name_two_specific_mutation']) - index = self.Source_organism_scientific_name_two.findText(self.deposit_dict['Source_organism_scientific_name_two'], - QtCore.Qt.MatchFixedString) - self.Source_organism_scientific_name_two.setCurrentIndex(index) - self.Source_organism_gene_two.setText(self.deposit_dict['Source_organism_gene_two']) - self.Source_organism_strain_two.setText(self.deposit_dict['Source_organism_strain_two']) - index = self.Expression_system_scientific_name_two.findText( - self.deposit_dict['Expression_system_scientific_name_two'], QtCore.Qt.MatchFixedString) - self.Expression_system_scientific_name_two.setCurrentIndex(index) - - self.Expression_system_strain_two.setText(self.deposit_dict['Expression_system_strain_two']) - self.Expression_system_vector_type_two.setText(self.deposit_dict['Expression_system_vector_type_two']) - self.Expression_system_plasmid_name_two.setText(self.deposit_dict['Expression_system_plasmid_name_two']) - self.Manipulated_source_details_two.setText(self.deposit_dict['Manipulated_source_details_two']) - self.molecule_chain_two.setText(self.deposit_dict['molecule_chain_two']) - self.molecule_one_letter_sequence_uniprot_id_two.setText( - self.deposit_dict['molecule_two_letter_sequence_uniprot_id']) - self.molecule_one_letter_sequence_two.setText(self.deposit_dict['molecule_two_letter_sequence']) -# except KeyError: -# self.molecule_chain_one.setText('') -# ### entity 2 -# self.molecule_name_two.setText('') -# self.fragment_name_two_specific_mutation.setText('') -# self.Source_organism_scientific_name_two.setCurrentIndex(0) -# self.Source_organism_gene_two.setText('') -# self.Source_organism_strain_two.setText('') -# self.Expression_system_scientific_name_two.setCurrentIndex(0) -# self.Expression_system_strain_two.setText('') -# self.Expression_system_vector_type_two.setText('') -# self.Expression_system_plasmid_name_two.setText('') -# self.Manipulated_source_details_two.setText('') -# self.molecule_chain_two.setText('') -# self.molecule_one_letter_sequence_uniprot_id_two.setText('') -# self.molecule_one_letter_sequence_two.setText('') - - ### - - self.structure_keywords.setText(self.deposit_dict['structure_keywords']) - self.biological_assembly_chain_number.setText(self.deposit_dict['biological_assembly_chain_number']) - self.molecule_one_letter_sequence_uniprot_id.setText( - self.deposit_dict['molecule_one_letter_sequence_uniprot_id']) - self.molecule_one_letter_sequence.setText(self.deposit_dict['molecule_one_letter_sequence']) - self.SG_project_name.setText(self.deposit_dict['SG_project_name']) - self.full_name_of_SG_center.setText(self.deposit_dict['full_name_of_SG_center']) - - index = self.crystallization_method.findText(self.deposit_dict['crystallization_method'], - QtCore.Qt.MatchFixedString) - self.crystallization_method.setCurrentIndex(index) - - self.crystallization_pH.setText(self.deposit_dict['crystallization_pH']) - self.crystallization_temperature.setText(self.deposit_dict['crystallization_temperature']) - self.crystallization_details.setText(self.deposit_dict['crystallization_details']) - index = self.radiation_source.findText(self.deposit_dict['radiation_source'], QtCore.Qt.MatchFixedString) - self.radiation_source.setCurrentIndex(index) - - index = self.radiation_source_type.findText(self.deposit_dict['radiation_source_type'], - QtCore.Qt.MatchFixedString) - self.radiation_source_type.setCurrentIndex(index) - - self.radiation_wavelengths.setText(self.deposit_dict['radiation_wavelengths']) - index = self.radiation_detector.findText(self.deposit_dict['radiation_detector'], - QtCore.Qt.MatchFixedString) - self.radiation_detector.setCurrentIndex(index) - - index = self.radiation_detector_type.findText(self.deposit_dict['radiation_detector_type'], - QtCore.Qt.MatchFixedString) - self.radiation_detector_type.setCurrentIndex(index) - - self.data_collection_date.setText(self.deposit_dict['data_collection_date']) - self.data_collection_temperature.setText(self.deposit_dict['data_collection_temperature']) - self.data_collection_protocol.setText(self.deposit_dict['data_collection_protocol']) - - self.pdbx_starting_model.setText(self.deposit_dict['pdbx_starting_model']) - index = self.data_integration_software.findText(self.deposit_dict['data_integration_software'], - QtCore.Qt.MatchFixedString) - self.data_integration_software.setCurrentIndex(index) - index = self.phasing_software.findText(self.deposit_dict['phasing_software'], QtCore.Qt.MatchFixedString) - self.phasing_software.setCurrentIndex(index) - - except ValueError: - self.update_status_bar('Sorry, this is not a XChemExplorer deposit file!') - self.update_log.insert('Sorry, this is not a XChemExplorer deposit file!') - - def update_deposit_dict(self): - self.deposit_dict = { - 'contact_author_PI_salutation': str(self.contact_author_PI_salutation.text()), - 'contact_author_PI_first_name': str(self.contact_author_PI_first_name.text()), - 'contact_author_PI_last_name': str(self.contact_author_PI_last_name.text()), - 'contact_author_PI_middle_name': str(self.contact_author_PI_middle_name.text()), - 'contact_author_PI_role': str(self.contact_author_PI_role.currentText()), - 'contact_author_PI_organization_type': str(self.contact_author_PI_organization_type.currentText()), - 'contact_author_PI_organization_name': str(self.contact_author_PI_organization_name.text()), - 'contact_author_PI_email': str(self.contact_author_PI_email.text()), - 'contact_author_PI_address': str(self.contact_author_PI_address.text()), - 'contact_author_PI_city': str(self.contact_author_PI_city.text()), - 'contact_author_PI_State_or_Province': str(self.contact_author_PI_State_or_Province.text()), - 'contact_author_PI_Zip_Code': str(self.contact_author_PI_Zip_Code.text()), - 'contact_author_PI_Country': str(self.contact_author_PI_Country.text()), - 'contact_author_PI_phone_number': str(self.contact_author_PI_phone_number.text()), - - 'contact_author_salutation': str(self.contact_author_salutation.text()), - 'contact_author_first_name': str(self.contact_author_first_name.text()), - 'contact_author_last_name': str(self.contact_author_last_name.text()), - 'contact_author_middle_name': str(self.contact_author_middle_name.text()), - 'contact_author_role': str(self.contact_author_role.currentText()), - 'contact_author_organization_type': str(self.contact_author_organization_type.currentText()), - 'contact_author_organization_name': str(self.contact_author_organization_name.text()), - 'contact_author_email': str(self.contact_author_email.text()), - 'contact_author_address': str(self.contact_author_address.text()), - 'contact_author_city': str(self.contact_author_city.text()), - 'contact_author_State_or_Province': str(self.contact_author_State_or_Province.text()), - 'contact_author_Zip_Code': str(self.contact_author_Zip_Code.text()), - 'contact_author_Country': str(self.contact_author_Country.text()), - 'contact_author_phone_number': str(self.contact_author_phone_number.text()), - - 'Release_status_for_coordinates': str(self.Release_status_for_coordinates.currentText()), - 'Release_status_for_sequence': str(self.Release_status_for_sequence.currentText()), - - 'group_deposition_title': str(self.group_deposition_title.text()), - 'group_description': str(self.group_description.text()), - - 'structure_title': str(self.structure_title.text()), - 'structure_title_apo': str(self.structure_title_apo.text()), - - 'primary_citation_id': str(self.primary_citation_id.text()), - 'primary_citation_journal_abbrev': str(self.primary_citation_journal_abbrev.text()), - 'primary_citation_title': str(self.primary_citation_title.text()), - 'primary_citation_year': str(self.primary_citation_year.text()), - 'primary_citation_journal_volume': str(self.primary_citation_journal_volume.text()), - 'primary_citation_page_first': str(self.primary_citation_page_first.text()), - 'primary_citation_page_last': str(self.primary_citation_page_last.text()), - ### entity 1 - 'molecule_name': str(self.molecule_name.text()), - 'Source_organism_scientific_name': str(self.Source_organism_scientific_name.currentText()), - 'Source_organism_gene': str(self.Source_organism_gene.text()), - 'Source_organism_strain': str(self.Source_organism_strain.text()), - 'Expression_system_scientific_name': str(self.Expression_system_scientific_name.currentText()), - 'Expression_system_strain': str(self.Expression_system_strain.text()), - 'Expression_system_plasmid_name': str(self.Expression_system_plasmid_name.text()), - 'Expression_system_vector_type': str(self.Expression_system_vector_type.text()), - 'Manipulated_source_details': str(self.Manipulated_source_details.text()), - 'fragment_name_one_specific_mutation': str(self.fragment_name_one_specific_mutation.text()), - 'molecule_chain_one': str(self.molecule_chain_one.text()), - - ### entity 2 - 'molecule_name_two': str(self.molecule_name_two.text()), - 'Source_organism_scientific_name_two': str(self.Source_organism_scientific_name_two.currentText()), - 'Source_organism_gene_two': str(self.Source_organism_gene_two.text()), - 'Source_organism_strain_two': str(self.Source_organism_strain_two.text()), - 'Expression_system_scientific_name_two': str(self.Expression_system_scientific_name_two.currentText()), - 'Expression_system_strain_two': str(self.Expression_system_strain_two.text()), - 'Expression_system_plasmid_name_two': str(self.Expression_system_plasmid_name_two.text()), - 'Expression_system_vector_type_two': str(self.Expression_system_vector_type_two.text()), - 'Manipulated_source_details_two': str(self.Manipulated_source_details_two.text()), - 'fragment_name_two_specific_mutation': str(self.fragment_name_two_specific_mutation.text()), - 'molecule_chain_two': str(self.molecule_chain_two.text()), - - 'structure_keywords': str(self.structure_keywords.text()), - 'biological_assembly_chain_number': str(self.biological_assembly_chain_number.text()), - 'molecule_one_letter_sequence_uniprot_id': str(self.molecule_one_letter_sequence_uniprot_id.text()), - 'molecule_two_letter_sequence_uniprot_id': str(self.molecule_one_letter_sequence_uniprot_id_two.text()), - 'SG_project_name': str(self.SG_project_name.text()), - 'full_name_of_SG_center': str(self.full_name_of_SG_center.text()), - 'molecule_one_letter_sequence': str(self.molecule_one_letter_sequence.toPlainText()).replace(' ', - '').replace( - '\n', '').replace('\r', ''), - 'molecule_two_letter_sequence': str(self.molecule_one_letter_sequence_two.toPlainText()).replace(' ', - '').replace( - '\n', '').replace('\r', ''), - - 'crystallization_method': str(self.crystallization_method.currentText()), - 'crystallization_pH': str(self.crystallization_pH.text()), - 'crystallization_temperature': str(self.crystallization_temperature.text()), - 'crystallization_details': str(self.crystallization_details.text()), - - 'radiation_source': str(self.radiation_source.currentText()), - 'radiation_source_type': str(self.radiation_source_type.currentText()), - 'radiation_wavelengths': str(self.radiation_wavelengths.text()), - 'radiation_detector': str(self.radiation_detector.currentText()), - 'radiation_detector_type': str(self.radiation_detector_type.currentText()), - 'data_collection_date': str(self.data_collection_date.text()), - 'data_collection_temperature': str(self.data_collection_temperature.text()), - 'data_collection_protocol': str(self.data_collection_protocol.text()), - 'pdbx_starting_model': str(self.pdbx_starting_model.text()), - 'data_integration_software': str(self.data_integration_software.currentText()), - 'phasing_software': str(self.phasing_software.currentText()) - } - - structure_author_name = '' - for widget in self.structure_author_name_List: - structure_author_name += str(widget.text()) + ';' - self.deposit_dict['structure_author_name'] = structure_author_name[:-1] - - primary_citation_author_name = '' - for widget in self.primary_citation_author_name_List: - primary_citation_author_name += str(widget.text()) + ';' - self.deposit_dict['primary_citation_author_name'] = primary_citation_author_name[:-1] - - def set_primary_citation_as_structure_authors(self, state): - if state == QtCore.Qt.Checked: - for n, entry in enumerate(self.structure_author_name_List): - self.primary_citation_author_name_List[n].setText(str(entry.text())) - else: - for n, entry in enumerate(self.primary_citation_author_name_List): - entry.setText('') - - def set_xce_logfile(self): - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'Save file', self.current_directory)) - self.xce_logfile = str(file_name) - self.xce_logfile_label.setText(str(self.xce_logfile)) - if self.xce_logfile == '' or self.xce_logfile[self.xce_logfile.rfind('/') + 1:] == '': - print('==> XCE: invalid file format') - else: - XChemLog.startLog(self.xce_logfile).create_logfile(self.xce_version) - self.update_log = XChemLog.updateLog(self.xce_logfile) - - def set_second_cif_file(self): - filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Select CIF File', - self.initial_model_directory, '*.cif') - filepath = str(tuple(filepath_temp)[0]) - self.second_cif_file = str(filepath) - self.second_cif_file_label.setText(str(self.second_cif_file)) - self.update_log.insert('user selected %s as CIF file for merging into ligand CIF files' %self.second_cif_file) - - def select_datasource_columns_to_display(self): - columns_to_show = QtGui.QMessageBox() - columns_to_showLayout = columns_to_show.layout() - columns_in_data_source = self.db.return_column_list() - try: - columns_in_data_source = self.db.return_column_list() - except AttributeError: - print('==> XCE: please select a datasource file') - self.status_bar.showMessage('please select a datasource file') - return - - column_dict = {} - vbox = QtGui.QVBoxLayout() - number_of_entries = len(columns_in_data_source) - columns_shown_in_dialog_column = 15 - grid = QtGui.QGridLayout() - x = 0 - y = 0 - columns_to_ignore = self.db.columns_not_to_display() - for entries_added in range(number_of_entries): - if not columns_in_data_source[entries_added][1] in columns_to_ignore: - data_source_column = QtGui.QCheckBox(columns_in_data_source[entries_added][1]) - column_dict[entries_added] = data_source_column - if columns_in_data_source[entries_added][1] in self.overview_datasource_table_columns: - data_source_column.setChecked(True) - grid.addWidget(data_source_column, y, x) - y += 1 - if y == columns_shown_in_dialog_column: - y = 0 - x += 1 - vbox.addLayout(grid) - columns_to_showLayout.addLayout(vbox, 0, 0) - - columns_to_show.addButton(QtGui.QPushButton('OK'), QtGui.QMessageBox.YesRole) - columns_to_show.addButton(QtGui.QPushButton('Cancel'), QtGui.QMessageBox.RejectRole) - reply = columns_to_show.exec_(); - if reply == 0: - columns_to_show_list = ['Sample ID'] - for key in column_dict: - if column_dict[key].isChecked(): - columns_to_show_list.append(columns_in_data_source[key][1]) - self.overview_datasource_table_columns = columns_to_show_list - self.populate_and_update_datasource_table() - - def update_header_and_data_from_datasource(self): - self.update_log.insert('getting information for all samples from data source...') - self.db = XChemDB.data_source(os.path.join(self.database_directory, self.data_source_file)) - self.update_log.insert('creating missing columns in data source') - self.db.create_missing_columns() - self.update_log.insert('load header and data from data source') - self.header, self.data = self.db.load_samples_from_data_source() - self.update_log.insert('get all samples in data source') - all_samples_in_db = self.db.execute_statement("select CrystalName from mainTable where CrystalName is not '';") - - self.xtal_db_dict = {} - sampleID_column = 0 - for n, entry in enumerate(self.header): - if entry == 'CrystalName': - sampleID_column = n - break - for line in self.data: - if str(line[sampleID_column]) != '': - db_dict = {} - for n, entry in enumerate(line): - if n != sampleID_column: - db_dict[str(self.header[n])] = str(entry) - self.xtal_db_dict[str(line[sampleID_column])] = db_dict - - print('==> XCE: found ' + str(len(self.xtal_db_dict)) + ' samples') - - def datasource_menu_save_samples(self): - print('hallo') - - def datasource_menu_export_csv_file(self): - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'Save file', self.database_directory)) - if file_name.rfind('.') != -1: - file_name = file_name[:file_name.rfind('.')] + '.csv' - else: - file_name = file_name + '.csv' - self.db.export_to_csv_file(file_name) - - def datasource_menu_import_csv_file(self): - if self.data_source_set: - file_name = QtGui.QFileDialog.getOpenFileName(self.window, 'Open file', self.database_directory) - self.db.import_csv_file(file_name) - else: - self.update_status_bar('Please load a data source file first') - - def datasource_menu_update_datasource(self): - self.work_thread = XChemThread.synchronise_db_and_filesystem(self.initial_model_directory, - os.path.join(self.database_directory, - self.data_source_file), - self.panddas_directory, self.xce_logfile, - 'project_directory') - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.work_thread.start() - - def export_data_for_WONKA(self): - self.update_log.insert('exporting CSV file for input into WONKA') - self.db.export_csv_for_WONKA() - - def on_context_menu(self, point): - # show context menu - for key in self.dewar_configuration_dict: - if self.dewar_configuration_dict[key] == self.sender(): - self.dewar_label_active = key - self.popMenu.exec_(self.sender().mapToGlobal(point)) - - - - def on_context_menu_reprocess_data(self, point): - # show context menu - self.popMenu_for_datasets_reprocess_table.exec_(self.sender().mapToGlobal(point)) - - def flag_sample_for_recollection(self): - self.dewar_configuration_dict[self.dewar_label_active].setStyleSheet("background-color: yellow") - - def undo_flag_sample_for_recollection(self): - self.dewar_configuration_dict[self.dewar_label_active].setStyleSheet("background-color: gray") - - def show_html_summary_in_firefox(self, xtal): - html_summary = self.albula_button_dict[xtal][2] - print('html_summary', html_summary) - new = 2 - webbrowser.open(html_summary, new=new) - - def update_pandda_crystal_from_combobox(self): - self.pandda_analyse_crystal_from_selection_combobox.clear() - self.pandda_analyse_crystal_from_selection_combobox.addItem('use all datasets') - if os.path.isfile(os.path.join(self.database_directory, self.data_source_file)): - self.load_crystal_form_from_datasource() - if self.xtalform_dict != {}: - print(self.xtalform_dict) - for key in self.xtalform_dict: - self.pandda_analyse_crystal_from_selection_combobox.addItem(key) - - def populate_reference_combobox(self, combobox): - combobox.clear() - for reference_file in self.reference_file_list: - combobox.addItem(reference_file[0]) - - - - def populate_refinement_outcome_combobox(self, combobox): - combobox.clear() - for stage in self.refinement_stage: - combobox.addItem(stage) - - - - def populate_target_selection_combobox(self, combobox): - combobox.clear() - for target in self.target_list: - combobox.addItem(target) - - def combo_selected(self, text): - self.map_url = str(self.panddas_directory + '/analyses/html_summaries/pandda_map_' + text + '.html') - self.pandda_maps_html.load(QtCore.QUrl(self.map_url)) - self.pandda_maps_html.show() - - def add_map_html(self): - self.map_list = glob.glob(str(self.panddas_directory + '/analyses/html_summaries/pandda_map_*.html')) - self.list_options = [] - for i in range(0, len(self.map_list)): - string = self.map_list[i] - string = string.replace('/analyses/html_summaries/pandda_map_', '') - string = string.replace('.html', '') - string = string.replace(self.panddas_directory, '') - self.list_options.append(string) - self.pandda_map_list.clear() - for i in range(0, len(self.list_options)): - self.pandda_map_list.addItem(self.list_options[i]) - self.connect(self.pandda_map_list, QtCore.SIGNAL('activated(QString)'), self.combo_selected) - - def open_config_file(self): - file_name_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Open file', self.current_directory, - '*.conf') - file_name = tuple(file_name_temp)[0] - - try: - pickled_settings = pickle.load(open(file_name, 'rb')) - - except: - print('==> XCE: failed to open config file...') - - key_list = {#'beamline_directory': 'beamline_directory', - 'initial_model_directory': 'initial_model_directory', - 'panddas_directory': 'panddas_directory', - 'html_export_directory': 'html_export_directory', - 'group_deposit_directory': 'group_deposit_directory', - 'database_directory': 'database_directory', - 'datasets_summary_file': 'datasets_summary', - #"'data_source_file': 'data_source', - 'ccp4_scratch_directory': 'ccp4_scratch', - 'allowed_unitcell_difference_percent': 'unitcell_difference', - 'acceptable_low_resolution_limit_for_data': 'too_low_resolution_data', - #'reference_directory_temp': 'reference_directory' - } -# self.pandda_input_data_dir_entry.setText(os.path.join(self.initial_model_directory, '*')) - - for current_key in key_list: - try: - command = str('self.' + current_key + " = pickled_settings['" + key_list[current_key] +"']") - exec(command) - command = str('self.settings["' + key_list[current_key]+ '"]= self.' + current_key) - exec(command) - print('==> XCE: found ' + key_list[current_key]) - except: - print('==> XCE: WARNING: Failed to find settings for: ' + key_list[current_key] + ' Error type: ' - + str(sys.exc_info()[0])) - exec(str(current_key + " = ''")) - continue - - - try: - pickled_settings = pickle.load(open(file_name, "rb")) - if pickled_settings['beamline_directory'] != self.beamline_directory: - self.beamline_directory = pickled_settings['beamline_directory'] - self.target_list, self.visit_list = XChemMain.get_target_and_visit_list(self.beamline_directory,self.read_agamemnon.isChecked()) - self.settings['beamline_directory'] = self.beamline_directory - self.populate_target_selection_combobox(self.target_selection_combobox) - - - self.layout_funcs.pandda_html(self) - self.show_pandda_html_summary() - - self.html_export_directory_label.setText(self.html_export_directory) - - self.group_deposition_directory_label.setText(self.group_deposit_directory) - - self.datasets_summary_file_label.setText(self.datasets_summary_file) - - self.data_source_file = pickled_settings['data_source'] - if self.data_source_file != '': - self.settings['data_source'] = os.path.join(self.database_directory, self.data_source_file) - # this is probably not necessary - if os.path.isfile(self.settings['data_source']): - write_enabled = self.check_write_permissions_of_data_source() - if not write_enabled: - self.data_source_file_label.setText('') - self.data_source_set = False - else: - self.data_source_file_label.setText( - os.path.join(self.database_directory, self.data_source_file)) - self.data_source_set = True - self.db = XChemDB.data_source(os.path.join(self.database_directory, self.data_source_file)) - self.datasource_menu_reload_samples() - - reference_directory_temp = pickled_settings['reference_directory'] - if reference_directory_temp != self.reference_directory: - self.reference_directory = reference_directory_temp - self.settings['reference_directory'] = self.reference_directory - self.update_reference_files(' ') - for xtal in self.initial_model_dimple_dict: - reference_file_selection_combobox = self.initial_model_dimple_dict[xtal][1] - self.populate_reference_combobox(reference_file_selection_combobox) - - self.initial_model_directory_label.setText(self.initial_model_directory) - self.panddas_directory_label.setText(self.panddas_directory) - self.pandda_output_data_dir_entry.setText(self.panddas_directory) - self.reference_directory_label.setText(self.reference_directory) - self.beamline_directory_label.setText(self.beamline_directory) - self.ccp4_scratch_directory_label.setText(self.ccp4_scratch_directory) - self.reference_file_list = self.get_reference_file_list(' ') - self.pandda_input_data_dir_entry.setText(os.path.join(self.initial_model_directory, '*')) - - self.update_all_tables() - - except KeyError: - self.update_status_bar('Sorry, this is not a XChemExplorer config file!') - self.update_log.insert('Sorry, this is not a XChemExplorer config file!') - - except: - print "Unexpected error:", sys.exc_info()[0] - raise - - def save_config_file(self): - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'Save file', self.current_directory)) - # make sure that the file always has .conf extension - if str(file_name).rfind('.') != -1: - file_name = file_name[:file_name.rfind('.')] + '.conf' - else: - file_name = file_name + '.conf' - pickle.dump(self.settings, open(file_name, 'wb')) - - def update_reference_files(self, reference_root): - self.reference_file_list = self.get_reference_file_list(reference_root) - self.populate_reference_combobox(self.reference_file_selection_combobox) - self.populate_reference_combobox(self.pandda_reference_file_selection_combobox) - - - - def check_status_rerun_dimple_on_all_autoprocessing_files(self): - print('hallo') - - def rerun_dimple_on_all_autoprocessing_files(self): - job_list = [] - self.update_log.insert('preparing to run DIMPLE on all autoprocessing files') - for xtal in self.data_collection_dict: - for entry in self.data_collection_dict[xtal]: - if entry[0] == 'logfile': - db_dict = entry[6] - try: - if os.path.isfile(os.path.join(db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName'])) or \ - os.path.isfile(os.path.join(db_dict['DataProcessingPathToMTZfile'])): - job_list = self.get_job_list_for_dimple_rerun(xtal, job_list, db_dict, entry) - except KeyError: - try: - if os.path.isfile(os.path.join(db_dict['DataProcessingPathToMTZfile'])): - job_list = self.get_job_list_for_dimple_rerun(xtal, job_list, db_dict, entry) - except KeyError: - continue - if job_list: - self.update_log.insert('trying to run DIMPLE on ALL auto-processing files') - self.check_before_running_dimple(job_list) - - def run_dimple_on_selected_autoprocessing_file(self): - job_list = [] - for xtal in sorted(self.initial_model_dimple_dict): - # print(xtal) - if self.initial_model_dimple_dict[xtal][0].isChecked(): - # print(xtal + ' is checked...') - db_dict = self.xtal_db_dict[xtal] - - # the if statement below is so convoluted, so that it is compatible with older data source files - - if os.path.isfile( - os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName'])) or \ - os.path.isfile( - os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'])) or \ - os.path.isfile(os.path.join(db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName'])) or \ - os.path.isfile(os.path.join(db_dict['DataProcessingPathToMTZfile'])): - - if os.path.isfile( - os.path.join(db_dict['DataProcessingPathToMTZfile'], db_dict['DataProcessingMTZfileName'])): - mtzin = os.path.join(db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName']) - elif os.path.isfile(os.path.join(db_dict['DataProcessingPathToMTZfile'])): - mtzin = os.path.join(db_dict['DataProcessingPathToMTZfile']) - elif os.path.isfile( - os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName'])): - mtzin = os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName']) - elif os.path.isfile( - os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'])): - mtzin = os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile']) - - reference_file = str(self.initial_model_dimple_dict[xtal][1].currentText()) - - reference_file_pdb = os.path.join(self.reference_directory, reference_file + '.pdb') - - if not os.path.isfile(reference_file_pdb): - continue - - if os.path.isfile(os.path.join(self.reference_directory, reference_file + '.mtz')): - reference_file_mtz = ' -R ' + os.path.join(self.reference_directory, reference_file + '.mtz') - else: - reference_file_mtz = '' - - if os.path.isfile(os.path.join(self.reference_directory, reference_file + '.cif')): - reference_file_cif = ' --libin ' + os.path.join(self.reference_directory, - reference_file + '.cif') - else: - reference_file_cif = '' - - job_list.append([xtal, - 'dimple_rerun_on_selected_file', - mtzin, - reference_file_pdb, - reference_file_mtz, - reference_file_cif]) - else: - print('WARNING: ' + xtal + ' has not been submitted to dimple because no files were found: ') - if not os.path.isfile(os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName'])): - print(' ' + str(os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'], - db_dict['DataProcessingMTZfileName'])) + ' is missing') - if not os.path.isfile(os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'])): - print(' ' + str(os.path.join(db_dict['ProjectDirectory'], xtal, db_dict['DataProcessingPathToMTZfile'])) + ' is missing') - if not os.path.isfile(os.path.join(db_dict['DataProcessingPathToMTZfile'])): - print(' ' + str(os.path.join(db_dict['DataProcessingPathToMTZfile']) + ' is missing')) - - - if job_list: - self.update_log.insert('trying to run DIMPLE on SELECTED auto-processing files') - self.check_before_running_dimple(job_list) - - def remove_selected_dimple_files(self): - job_list = [] - for xtal in sorted(self.initial_model_dimple_dict): - if self.initial_model_dimple_dict[xtal][0].isChecked(): - job_list.append(xtal) - - if job_list: - msgBox = QtGui.QMessageBox() - msgBox.setText("Do you really want to delete {0!s} {1!s} files?".format(len(job_list),self.preferences['initial_refinement_pipeline'])) - msgBox.addButton(QtGui.QPushButton('Go'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('Cancel'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - - if reply == 0: - self.status_bar.showMessage('preparing to remove DIMPLE files') - self.update_log.insert('preparing to remove DIMPLE files') - self.work_thread = XChemThread.remove_selected_dimple_files(job_list, - self.initial_model_directory, - self.xce_logfile, - self.database_directory, - self.data_source_file, - self.preferences['initial_refinement_pipeline']) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.work_thread.start() - - def set_results_from_selected_pipeline(self): - self.update_log.warning('selecting initial refinement results from '+self.preferences['initial_refinement_pipeline']) - - job_list = [] - for xtal in sorted(self.initial_model_dimple_dict): - if self.initial_model_dimple_dict[xtal][0].isChecked(): - job_list.append(xtal) - - self.work_thread = XChemThread.set_results_from_selected_pipeline(job_list, - self.initial_model_directory, - self.xce_logfile, - self.database_directory, - self.data_source_file, - self.preferences['initial_refinement_pipeline']) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.work_thread.start() - - - - def run_xia2_on_selected_datasets(self, overwrite): - - # check which programs should be run - protocol = [] - if self.xia2_3d_checkbox.isChecked(): - protocol.append('3d') - if self.xia2_3dii_checkbox.isChecked(): - protocol.append('3dii') - if self.xia2_dials_checkbox.isChecked(): - protocol.append('dials') - - # space group - spg = [] - if str(self.reprocess_space_group_comboxbox.currentText()) != 'ignore': - spg.append(str(self.reprocess_space_group_comboxbox.currentText())) - - # reference file - ref = [] - if os.path.isfile(self.diffraction_data_reference_mtz): - ref.append(self.diffraction_data_reference_mtz) - - # resolution limit - reso_limit = [] - if str(self.reprocess_isigma_combobox.currentText()) != 'default': - reso_limit.append(str(self.reprocess_isigma_combobox.currentText())) - - # cc 1/2 - cc_half = [] - if str(self.reprocess_cc_half_combobox.currentText()) != 'default': - cc_half.append(str(self.reprocess_cc_half_combobox.currentText())) - - run_dict = {} - allRows = self.datasets_reprocess_table.rowCount() - for row in xrange(0, allRows): - dataset_id = str(self.datasets_reprocess_table.item(row, 0).text()) - sample_id = str(self.datasets_reprocess_table.item(row, 1).text()) - if self.diffraction_data_table_dict[dataset_id][0].isChecked(): - run_dict[sample_id] = self.diffraction_data_dict[dataset_id] - - if protocol != [] and run_dict != {}: - self.work_thread = XChemProcess.run_xia2(self.initial_model_directory, - run_dict, - protocol, - spg, - ref, - reso_limit, - cc_half, - self.xce_logfile, - self.external_software, - self.ccp4_scratch_directory, - self.max_queue_jobs, - os.path.join(self.database_directory, self.data_source_file), - overwrite) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - else: - self.update_log.insert('please select datasets and/ or data processing protocol') - self.update_status_bar('please select datasets and/ or data processing protocol') - - def update_reprocessing_table(self): - allRows = self.datasets_reprocess_table.rowCount() - for row in xrange(0, allRows): - sample_id = str(self.datasets_reprocess_table.item(row, 1).text()) - if sample_id in self.xtal_db_dict: - db_dict = self.xtal_db_dict[sample_id] - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(db_dict['DataProcessingStatus']) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - if db_dict['DataProcessingStatus'] == 'running': - cell_text.setBackground(QtGui.QColor(100, 230, 150)) - elif db_dict['DataProcessingStatus'] == 'pending': - cell_text.setBackground(QtGui.QColor(20, 100, 230)) - elif db_dict['DataProcessingStatus'] == 'started': - cell_text.setBackground(QtGui.QColor(230, 240, 110)) - elif db_dict['DataProcessingStatus'] == 'finished': - cell_text.setBackground(QtGui.QColor(255, 255, 255)) - self.datasets_reprocess_table.setItem(row, 7, cell_text) - - def get_job_list_for_dimple_rerun(self, xtal, job_list, db_dict, entry): - self.status_bar.showMessage('checking: ' + str( - os.path.join(db_dict['DataProcessingPathToMTZfile'], db_dict['DataProcessingMTZfileName']))) - suitable_reference = [] - for reference in self.reference_file_list: - # first we need one in the same pointgroup - if reference[5] == db_dict['DataProcessingPointGroup']: - try: - difference = math.fabs(1 - (float(db_dict['DataProcessingUnitCellVolume']) / float(reference[4]))) - suitable_reference.append([reference[0], difference]) - except ValueError: - continue - if suitable_reference: - reference_file = min(suitable_reference, key=lambda x: x[1])[0] - visit = entry[1] - run = entry[2] - autoproc = entry[4] - - reference_file_pdb = os.path.join(self.reference_directory, reference_file + '.pdb') - - if os.path.isfile(os.path.join(self.reference_directory, reference_file + '.mtz')): - reference_file_mtz = ' -R ' + os.path.join(self.reference_directory, reference_file + '.mtz') - else: - reference_file_mtz = '' - - if os.path.isfile(os.path.join(self.reference_directory, reference_file + '.cif')): - reference_file_cif = ' --libin ' + os.path.join(self.reference_directory, reference_file + '.cif') - else: - reference_file_cif = '' - - if os.path.isfile(os.path.join(self.initial_model_directory, xtal, xtal +'.mtz')): - mtzin = os.path.join(self.initial_model_directory, xtal, xtal +'.mtz') - - self.update_log.insert('adding ' + xtal + visit + '-' + run + autoproc + ' to list') - job_list.append([xtal, - visit + '-' + run + autoproc, - mtzin, - reference_file_pdb, - reference_file_mtz, - reference_file_cif]) - self.status_bar.showMessage('idle') - return job_list - - def check_before_running_dimple(self, job_list): - - msgBox = QtGui.QMessageBox() - msgBox.setText( - "Do you really want to run {0!s} {1!s} jobs?\nNote: we will not run more than {2!s} at once on the cluster!".format( - len(job_list),self.preferences['initial_refinement_pipeline'],self.preferences['max_queue_jobs'])) - msgBox.addButton(QtGui.QPushButton('Go'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('Cancel'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - - if reply == 0: - self.status_bar.showMessage('preparing {0!s} DIMPLE jobs'.format(len(job_list))) - self.update_log.insert('preparing to run {0!s} DIMPLE jobs'.format(len(job_list))) - if self.external_software['qsub_array']: - self.update_log.insert('we will be running an ARRAY job on the DLS computer cluster') - self.update_log.insert( - 'please note that the maximum number of jobs that will be running at once is {0!s}'.format( - self.max_queue_jobs)) - self.update_log.insert( - 'you can change this in the PREFERENCES menu, but be warned that to high a number might break the cluster!') - self.update_log.insert('preparing input files for DIMPLE...') - self.work_thread = XChemThread.run_dimple_on_all_autoprocessing_files_new(job_list, - self.initial_model_directory, - self.external_software, - self.ccp4_scratch_directory, - self.database_directory, - self.data_source_file, - self.max_queue_jobs, - self.xce_logfile, - self.using_remote_qsub_submission, - self.remote_qsub_submission, - self.preferences['dimple_twin_mode'], - self.preferences['initial_refinement_pipeline']) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.work_thread.start() - - - - - - - - - - def open_csv_file_translate_datasetID_to_sampleID(self): - file_name_temp = QtGui.QFileDialog.getOpenFileNameAndFilter(self.window, 'Open file', self.current_directory, - '*.csv') - file_name = tuple(file_name_temp)[0] - self.translate_datasetID_to_sampleID_csv_label.setText(file_name) - self.translate_datasetID_to_sampleID_file = file_name - - - - def update_datasets_reprocess_table(self, data_dict): - self.update_log.insert('updating reprocess datasets table') - print('updating reprocess datasets table') - self.diffraction_data_table_dict = {} - self.diffraction_data_dict = data_dict - - self.diffraction_data_search_info = 'found ' + str(len(self.diffraction_data_dict)) + ' datasets' - self.diffraction_data_search_label.setText(self.diffraction_data_search_info) - self.update_log.insert(self.diffraction_data_search_info) - self.datasource_menu_reload_samples() - # update table - column_name = self.db.translate_xce_column_list_to_sqlite(self.datasets_reprocess_columns) - # set rows to 0 - self.datasets_reprocess_table.setRowCount(0) - for entry in sorted(self.diffraction_data_dict): - self.update_log.insert(str(self.diffraction_data_dict[entry])) - if entry in self.xtal_db_dict: - db_dict = self.xtal_db_dict[entry] - else: - db_dict = {} - row = self.datasets_reprocess_table.rowCount() - self.datasets_reprocess_table.insertRow(row) - for column, header in enumerate(column_name): - if header[0] == 'Dataset ID' or header[0] == 'Sample ID': - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(entry)) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.datasets_reprocess_table.setItem(row, column, cell_text) - elif header[0] == 'Run\nxia2': - run_xia2 = QtGui.QCheckBox() - run_xia2.toggle() - self.datasets_reprocess_table.setCellWidget(row, column, run_xia2) - run_xia2.setChecked(False) - self.diffraction_data_table_dict[entry] = [run_xia2] - else: - cell_text = QtGui.QTableWidgetItem() - if db_dict != {}: - if header[0] == 'DataProcessing\nStatus': - if str(db_dict[header[1]]) == 'running': - cell_text.setBackground(QtGui.QColor(100, 230, 150)) - elif str(db_dict[header[1]]) == 'pending': - cell_text.setBackground(QtGui.QColor(20, 100, 230)) - elif str(db_dict[header[1]]) == 'started': - cell_text.setBackground(QtGui.QColor(230, 240, 110)) - elif str(db_dict[header[1]]) == 'finished': - cell_text.setBackground(QtGui.QColor(255, 255, 255)) - cell_text.setText(str(db_dict[header[1]])) - else: - cell_text.setText('') - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.datasets_reprocess_table.setItem(row, column, cell_text) - - def update_all_tables(self): - self.update_log.insert('checking for new reference files') - self.update_status_bar('checking for new reference files') - self.reference_file_list = self.get_reference_file_list(' ') - self.update_log.insert('updating Overview table') - self.update_status_bar('updating Overview table') - self.populate_and_update_datasource_table() - self.update_log.insert('updating Maps table') - self.update_status_bar('updating Maps table') - self.create_maps_table() - self.update_log.insert('updating PANDDA table') - self.update_status_bar('updating PANDDA table') - self.populate_pandda_analyse_input_table() - self.update_log.insert('updating REFINEMENT table') - self.update_status_bar('updating REFINEMENT table') - self.populate_and_update_refinement_table() - self.update_log.insert('updating REPROCESSING table') - self.update_status_bar('updating REPROCESSING table') - self.update_reprocessing_table() - self.update_status_bar('idle') - self.update_summary_plot() - - - - def change_allowed_unitcell_difference_percent(self, text): - try: - self.allowed_unitcell_difference_percent = int(text) - self.settings['unitcell_difference'] = self.allowed_unitcell_difference_percent - self.update_log.insert( - 'changing max allowed unit cell difference between reference and xtal to {0!s} percent'.format( - self.allowed_unitcell_difference_percent)) - except ValueError: - if str(text).find('.') != -1: - self.allowed_unitcell_difference_percent = int(str(text)[:str(text).find('.')]) - self.settings['unitcell_difference'] = self.allowed_unitcell_difference_percent - self.update_log.insert( - 'changing max allowed unit cell difference between reference and xtal to {0!s} percent'.format( - self.allowed_unitcell_difference_percent)) - else: - pass - - def change_max_queue_jobs(self, text): - try: - self.max_queue_jobs = int(text) - self.settings['max_queue_jobs'] = self.max_queue_jobs - self.update_log.insert('changing max number of jobs running simultaneously on DLS cluster to {0!s}'.format( - self.max_queue_jobs)) - except ValueError: - if str(text).find('.') != -1: - self.max_queue_jobs = int(str(text)[:str(text).find('.')]) - self.settings['max_queue_jobs'] = self.max_queue_jobs - self.update_log.insert( - 'changing max number of jobs running simultaneously on DLS cluster to {0!s}'.format( - self.max_queue_jobs)) - else: - pass - - def change_acceptable_low_resolution_limit(self, text): - try: - self.acceptable_low_resolution_limit_for_data = float(text) - self.settings['too_low_resolution_data'] = self.acceptable_low_resolution_limit_for_data - except ValueError: - pass - - def change_filename_root(self, text): - self.filename_root = str(text) - self.settings['filename_root'] = self.filename_root - - def button_clicked(self): - if not self.data_source_set: - print('sender text bit') - if self.sender().text() == "Create New Data\nSource (SQLite)": - file_name = str(QtGui.QFileDialog.getSaveFileName(self.window, 'Save file', self.database_directory)) - # make sure that the file always has .sqlite extension - if file_name.rfind('.') != -1: - file_name = file_name[:file_name.rfind('.')] + '.sqlite' - else: - file_name = file_name + '.sqlite' - self.db = XChemDB.data_source(file_name) - print('==> XCE: creating new data source') - self.db.create_empty_data_source_file() - self.db.create_missing_columns() - if self.data_source_file == '': - self.database_directory = file_name[:file_name.rfind('/')] - self.data_source_file = file_name[file_name.rfind('/') + 1:] - self.data_source_file_label.setText(os.path.join(self.database_directory, self.data_source_file)) - self.settings['database_directory'] = self.database_directory - self.settings['data_source'] = self.data_source_file - self.data_source_set = True - else: - self.no_data_source_selected() - print('No datasource selected') - pass - - # first find out which of the 'Run' or 'Status' buttons is sending - for item in self.workflow_widget_dict: - for widget in self.workflow_widget_dict[item]: - if widget == self.sender(): - # get index of item in self.workflow; Note this index should be the same as the index - # of the self.main_tab_widget which belongs to this task - task_index = self.workflow.index(item) - instruction = str(self.workflow_widget_dict[item][0].currentText()) - print(instruction) - action = str(self.sender().text()) - if self.main_tab_widget.currentIndex() == task_index: - if self.explorer_active == 0 and self.data_source_set == True: - if action == 'Run': - print('==> XCE: Remote submission status = ' + str(self.using_remote_qsub_submission)) - # print(instruction) - self.prepare_and_run_task(instruction) - elif action == 'Status': - self.get_status_of_workflow_milestone(instruction) - if os.path.exists(str(self.panddas_directory + '/pandda.done')): - self.pandda_status = 'Finished!' - self.pandda_status_label.setStyleSheet('color: green') - if os.path.exists(str(self.panddas_directory + '/pandda.running')): - self.pandda_status = 'Running...' - self.pandda_status_label.setStyleSheet('color: orange') - if os.path.exists(str(self.panddas_directory + '/pandda.errored')): - self.pandda_status = 'Error encountered... please check the log files for pandda!' - self.pandda_status_label.setStyleSheet('color: red') - self.pandda_status_label.setText(str('STATUS: ' + self.pandda_status)) - else: - self.need_to_switch_main_tab(task_index) - - def get_status_of_workflow_milestone(self, instruction): - # first update all tables - self.datasource_menu_reload_samples() - - cluster_dict = XChemMain.get_jobs_running_on_cluster() - - self.update_log.insert('getting status updates...') - - self.status_bar.showMessage('please check terminal window for further information') - - self.update_log.insert('{0!s} samples are currently in database'.format(str(len(self.xtal_db_dict)))) - - if 'DIMPLE' in instruction: - XChemMain.print_cluster_status_message('dimple', cluster_dict, self.xce_logfile) - - elif 'Create CIF/PDB/PNG file' in instruction: - XChemMain.print_acedrg_status(self.xce_logfile, self.xtal_db_dict) - XChemMain.print_cluster_status_message('acedrg', cluster_dict, self.xce_logfile) - - elif instruction.startswith('Run xia2 on selected datasets'): - XChemMain.print_cluster_status_message('xia2', cluster_dict, self.xce_logfile) - - elif 'pandda' in instruction.lower(): - XChemMain.print_cluster_status_message('pandda', cluster_dict, self.xce_logfile) - - elif 'coot' in instruction.lower(): - XChemMain.print_cluster_status_message('refmac', cluster_dict, self.xce_logfile) - - def prepare_and_run_task(self, instruction): - - if instruction == 'Get New Results from Autoprocessing': - self.rescore = False - self.check_for_new_autoprocessing_results() - - elif instruction == 'Rescore Datasets': - self.rescore = True - self.select_best_autoprocessing_result() - -# if instruction == 'Get New Results from Autoprocessing': -# self.check_for_new_autoprocessing_or_rescore(False) -# self.update_header_and_data_from_datasource() -# self.update_all_tables() -# -# elif instruction == 'Rescore Datasets': -# self.check_for_new_autoprocessing_or_rescore(True) - -# elif instruction == "Read PKL file": -# summary = pickle.load(open(self.datasets_summary_file, "rb")) -# self.create_widgets_for_autoprocessing_results_only(summary) - - elif instruction == 'Run xia2 on selected datasets': - self.run_xia2_on_selected_datasets(False) - - elif instruction == 'Run xia2 on selected datasets - overwrite': - self.run_xia2_on_selected_datasets(True) - -# elif instruction == 'Run DIMPLE on All Autoprocessing MTZ files': -# self.rerun_dimple_on_all_autoprocessing_files() - - elif instruction == 'Run initial refinement on selected MTZ files': - self.run_dimple_on_selected_autoprocessing_file() - - elif instruction == 'Remove selected initial refinement files': - self.remove_selected_dimple_files() - - elif instruction == 'Set only results from selected pipeline': - self.set_results_from_selected_pipeline() - -# elif instruction == 'Create CIF/PDB/PNG file of ALL compounds': -# self.create_cif_pdb_png_files('ALL') - -# elif instruction == 'Create CIF/PDB/PNG file of NEW compounds': -# self.create_cif_pdb_png_files('NEW') - - elif instruction == 'Create CIF/PDB/PNG file of SELECTED compounds': - self.create_cif_pdb_png_files('SELECTED') - - elif instruction == 'Merge ligand CIF file with selected compounds': - self.merge_cif_files('merge') - - elif instruction == 'Restore original CIF file of selected compounds': - self.merge_cif_files('restore') - - elif instruction == 'Fit ligands into maps after initial refinement': - self.fit_ligands_into_dimple_maps() - - elif instruction == 'pandda.analyse': - self.run_pandda_analyse('production_run') - - elif instruction == 'pre-run for ground state model': - self.run_pandda_analyse('pre_run') - - elif instruction == 'pandda.inspect': - self.run_pandda_inspect() - - elif instruction == 'run pandda.inspect at home': - self.run_pandda_inspect_at_home() - - elif instruction == 'Export NEW PANDDA models': - update_datasource_only = False - which_models = 'new' - self.run_pandda_export(update_datasource_only, which_models) - - elif instruction == 'Export ALL PANDDA models': - update_datasource_only = False - which_models = 'all' - self.run_pandda_export(update_datasource_only, which_models) - - elif instruction == 'cluster datasets': - self.cluster_datasets_for_pandda() - - elif instruction == 'Update datasource with results from pandda.inspect': - update_datasource_only = True - which_models = 'all' - self.run_pandda_export(update_datasource_only, which_models) - - elif instruction == 'Show HTML summary': - self.show_pandda_html_summary() - - elif instruction == 'Event Map -> SF': - self.convert_event_maps_to_SF() - - elif instruction == 'apo -> mmcif': - self.convert_apo_to_mmcif() - - elif instruction == 'check modelled ligands': - self.compare_modelled_ligands_and_panddaTable() - - elif instruction.startswith("Open COOT") or instruction == 'Build ground state model': - if not self.coot_running: - self.update_log.insert('starting coot...') - if instruction == "Open COOT": - interface = 'new' - elif instruction == "Open COOT - test -": - interface = 'test' - elif instruction == "Open COOT for old PanDDA": - interface = 'panddaV1' - elif instruction == 'Build ground state model': - interface = 'reference' - else: - interface = 'old' - print self.settings - self.work_thread = XChemThread.start_COOT(self.settings, interface) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - - elif instruction == 'Update Deposition Table': - self.update_deposition_table() - - - - def check_status_create_png_of_soaked_compound(self): - number_of_samples = 0 - running = 0 - timestamp_list = [] - cif_file_generated = 0 - for folder in glob.glob(os.path.join(self.initial_model_directory, '*', 'compound')): - number_of_samples += 1 - if os.path.isfile(os.path.join(folder, 'RESTRAINTS_IN_PROGRESS')): - running += 1 - timestamp = datetime.fromtimestamp( - os.path.getmtime(os.path.join(folder, 'RESTRAINTS_IN_PROGRESS'))).strftime('%Y-%m-%d %H:%M:%S') - timestamp_list.append(timestamp) - for cif_file in glob.glob(os.path.join(folder, '*.cif')): - if os.path.isfile(cif_file): - cif_file_generated += 1 - if timestamp_list: - last_timestamp = max(timestamp_list) - else: - last_timestamp = 'n/a' - message = 'Datasets: ' + str(number_of_samples) + ', jobs running: ' + str(running) + ', jobs finished: ' + str( - cif_file_generated) + ', last job submmitted: ' + str(last_timestamp) - self.status_bar.showMessage(message) - - - - if start_thread: - if self.target == '=== SELECT TARGET ===': - msgBox = QtGui.QMessageBox() - warning = ('*** WARNING ***\n' - 'You did not select a target!\n' - 'In this case we will only parse the project directory!\n' - 'Please note that this option is usually only useful in case you reprocessed your data.\n' - 'Do you want to continue?') - msgBox.setText(warning) - msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - start_thread = True - else: - start_thread = False - else: - start_thread = True - - if start_thread: - self.work_thread = XChemThread.read_autoprocessing_results_from_disc(self.visit_list, - self.target, - self.reference_file_list, - self.database_directory, - self.data_collection_dict, - self.preferences, - self.datasets_summary_file, - self.initial_model_directory, - rescore_only, - self.acceptable_low_resolution_limit_for_data, - os.path.join(self.database_directory, - self.data_source_file), - self.xce_logfile) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("create_widgets_for_autoprocessing_results_only"), - self.create_widgets_for_autoprocessing_results_only) - self.work_thread.start() - - def save_files_to_initial_model_folder(self): - self.work_thread = XChemThread.save_autoprocessing_results_to_disc(self.dataset_outcome_dict, - self.data_collection_table_dict, - self.data_collection_column_three_dict, - self.data_collection_dict, - self.database_directory, - self.data_source_file, - self.initial_model_directory, - self.preferences, - self.datasets_summary_file) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def run_pandda_analyse(self, run): - pandda_params = { - 'data_dir': str(self.pandda_input_data_dir_entry.text()), - 'out_dir': str(self.pandda_output_data_dir_entry.text()), - 'submit_mode': str(self.pandda_submission_mode_selection_combobox.currentText()), - 'nproc': str(self.pandda_nproc_entry.text()), - 'min_build_datasets': str(self.pandda_min_build_dataset_entry.text()), - 'pdb_style': str(self.pandda_pdb_style_entry.text()), - 'mtz_style': str(self.pandda_mtz_style_entry.text()), - 'sort_event': str(self.pandda_sort_event_combobox.currentText()), - 'average_map': str(self.pandda_calc_map_combobox.currentText()), - 'max_new_datasets': str(self.pandda_max_new_datasets_entry.text()), - 'grid_spacing': str(self.pandda_grid_spacing_entry.text()), - 'pandda_dir_structure': str(self.pandda_input_data_dir_entry.text()), - 'perform_diffraction_data_scaling': str(self.wilson_checkbox.isChecked()), - 'filter_pdb': str(self.pandda_reference_file_selection_combobox.currentText()), - 'reference_dir': self.reference_directory, - 'appendix': '', - 'N_datasets': len(glob.glob(os.path.join(self.initial_model_directory, '*', 'dimple.pdb'))), - 'write_mean_map': 'interesting', - 'pandda_table': self.pandda_analyse_data_table, - 'use_remote': self.using_remote_qsub_submission, - 'remote_string': self.remote_qsub_submission - } - - if run == 'pre_run': - msgBox = QtGui.QMessageBox() - msgBoxLayout = msgBox.layout() - vbox = QtGui.QVBoxLayout() - vbox.addWidget(QtGui.QLabel(XChemToolTips.pandda_pre_run(self.reference_directory))) - hbox = QtGui.QHBoxLayout() - hbox.addWidget(QtGui.QLabel('appendix:')) - appendix = QtGui.QLineEdit() - appendix.setText('pre') - appendix.setFixedWidth(200) - hbox.addWidget(appendix) - vbox.addLayout(hbox) - - msgBoxLayout.addLayout(vbox, 0, 0) - msgBox.addButton(QtGui.QPushButton('Go'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('Cancel'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - pandda_params['appendix'] = str(appendix.text()) - pandda_params['max_new_datasets'] = '100' - pandda_params['N_datasets'] = 100 - pandda_params['write_mean_map'] = 'all' - else: - return None - - self.update_log.insert('preparing pandda.analyse input script') - self.work_thread = XChemPANDDA.run_pandda_analyse(pandda_params, self.xce_logfile, - os.path.join(self.database_directory, self.data_source_file)) - self.work_thread = XChemPANDDA.run_pandda_analyse(pandda_params, self.xce_logfile, - os.path.join(self.database_directory, self.data_source_file)) - #self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - #self.datasource_menu_reload_samples) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def cluster_datasets_for_pandda(self): - - pandda_params = { - 'out_dir': str(self.pandda_output_data_dir_entry.text()), - 'pdb_style': str(self.pandda_pdb_style_entry.text()), - 'mtz_style': str(self.pandda_mtz_style_entry.text()) - } - self.update_log.insert('starting giant.cluster_mtzs_and_pdbs') - self.work_thread = XChemPANDDA.giant_cluster_datasets(self.initial_model_directory, pandda_params, - self.xce_logfile, os.path.join(self.database_directory, - self.data_source_file), - run_pandda_analyse) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def run_pandda_inspect(self): - self.settings['panddas_directory'] = str(self.pandda_output_data_dir_entry.text()) - print('==> XCE: starting pandda.inspect') - self.work_thread = XChemThread.start_pandda_inspect(self.settings, self.xce_logfile) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def run_pandda_inspect_at_home(self): - self.work_thread = XChemPANDDA.run_pandda_inspect_at_home(self.panddas_directory, self.xce_logfile) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - - def convert_event_maps_to_SF(self): - self.update_log.insert('converting all event maps in {0!s} to mtz files'.format(self.initial_model_directory)) -# self.work_thread = XChemPANDDA.convert_all_event_maps_in_database(self.initial_model_directory, -# self.xce_logfile, -# os.path.join(self.database_directory, -# self.data_source_file)) - self.work_thread = XChemPANDDA.find_event_map_for_ligand(self.initial_model_directory, - self.xce_logfile) - - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def convert_apo_to_mmcif(self): - self.work_thread = XChemPANDDA.convert_apo_structures_to_mmcif(self.panddas_directory, - self.xce_logfile) - - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - - def compare_modelled_ligands_and_panddaTable(self): - self.update_log.insert('checking agreement of ligands in refine.pdb and entries in panddaTable') - self.work_thread = XChemPANDDA.check_number_of_modelled_ligands(self.initial_model_directory, - self.xce_logfile, - os.path.join(self.database_directory, - self.data_source_file)) - self.explorer_active = 1 - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("show_error_dict"), self.show_error_dict) - self.work_thread.start() - - def run_pandda_export(self, update_datasource_only, which_models): - self.settings['panddas_directory'] = str(self.pandda_output_data_dir_entry.text()) - if update_datasource_only: - self.update_log.insert('updating data source with results from pandda.inspect') - else: - self.update_log.insert( - 'exporting PANDDA models, updating data source and launching inital refinement for new models') - - start_thread = False - if which_models == 'all': - self.update_log.insert('exporting ALL models! *** WARNING *** This may overwrite previous refinements!!!') - msgBox = QtGui.QMessageBox() - msgBox.setText("*** WARNING ***\nThis will overwrite all your manual selections!\nDo you want to continue?") - msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - if update_datasource_only: - self.update_log.insert('will update panddaTable in database only') - else: - self.update_log.insert('will export ALL models!') - start_thread = True - else: - start_thread = False - else: - self.update_log.insert('exporting new models only') - start_thread = True - - if start_thread: - self.work_thread = XChemPANDDA.run_pandda_export(self.panddas_directory, - os.path.join(self.database_directory, - self.data_source_file), - self.initial_model_directory, self.xce_logfile, - update_datasource_only, which_models) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.work_thread.start() - - def show_pandda_html_summary(self): - self.pandda_initial_html.load(QtCore.QUrl(self.pandda_initial_html_file)) - self.pandda_initial_html.show() - self.pandda_analyse_html.load(QtCore.QUrl(self.pandda_analyse_html_file)) - self.pandda_analyse_html.show() - self.add_map_html() - self.pandda_inspect_html.load(QtCore.QUrl(self.pandda_inspect_html_file)) - self.pandda_inspect_html.show() - - def create_cif_pdb_png_files(self, todo): - tmp = self.db.execute_statement( - "select CrystalName,CompoundCode,CompoundSmiles from mainTable where CrystalName is not '' and CompoundSmiles is not '' and CompoundSmiles is not NULL;") - compound_list = [] - for item in tmp: - if str(item[1]) == '' or str(item[1]) == 'NULL': - compoundID = 'compound' - else: - compoundID = str(item[1]) - - if todo == 'ALL': - compound_list.append([str(item[0]), compoundID, str(item[2])]) - elif todo == 'NEW': - if not os.path.isfile(os.path.join(self.initial_model_directory, str(item[0]), compoundID + '.cif')): - compound_list.append([str(item[0]), compoundID, str(item[2])]) - elif todo == 'SELECTED': - if str(item[0]) in self.initial_model_dimple_dict: - if self.initial_model_dimple_dict[str(item[0])][0].isChecked(): - compound_list.append([str(item[0]), compoundID, str(item[2])]) - - if compound_list: - self.update_log.insert( - 'trying to create cif and pdb files for ' + str(len(compound_list)) + ' compounds using ACEDRG...') - if self.external_software['qsub']: - self.update_log.insert( - 'will try sending ' + str(len(compound_list)) + ' jobs to your computer cluster!') - elif self.external_software['qsub_array']: - self.update_log.insert('will try sending ' + str( - len(compound_list)) + ' jobs as part of an ARRAY job to your computer cluster!') - else: - self.update_log.insert('apparently no cluster available, so will run ' + str( - len(compound_list)) + ' sequential jobs on one core of your local machine.') - self.update_log.insert('this could take a while...') - self.explorer_active = 1 - self.work_thread = XChemThread.create_png_and_cif_of_compound(self.external_software, - self.initial_model_directory, - compound_list, - self.database_directory, - self.data_source_file, - todo, - self.ccp4_scratch_directory, - self.xce_logfile, - self.max_queue_jobs, - self.restraints_program) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.work_thread.start() - - def fit_ligands_into_dimple_maps(self): - tmp = self.db.execute_statement( - "select CrystalName,CompoundCode,CompoundSmiles from mainTable where CrystalName is not '' and CompoundSmiles is not '' and CompoundSmiles is not NULL;") - compound_list = [] - for item in tmp: - if str(item[1]) == '' or str(item[1]) == 'NULL': - compoundID = 'compound' - else: - compoundID = str(item[1]) - - if str(item[0]) in self.initial_model_dimple_dict: - if self.initial_model_dimple_dict[str(item[0])][0].isChecked(): - compound_list.append([str(item[0]), compoundID, str(item[2])]) - - if compound_list: - self.update_log.insert( - 'trying to auto-fitting into inital maps for ' + str(len(compound_list)) + ' compounds...') - if self.external_software['qsub']: - self.update_log.insert( - 'will try sending ' + str(len(compound_list)) + ' jobs to your computer cluster!') - elif self.external_software['qsub_array']: - self.update_log.insert('will try sending ' + str( - len(compound_list)) + ' jobs as part of an ARRAY job to your computer cluster!') - else: - self.update_log.insert('apparently no cluster available, so will run ' + str( - len(compound_list)) + ' sequential jobs on one core of your local machine.') - self.update_log.insert('this could take a while...') - self.explorer_active = 1 - self.work_thread = XChemThread.fit_ligands(self.external_software, - self.initial_model_directory, - compound_list, - self.database_directory, - self.data_source_file, - self.ccp4_scratch_directory, - self.xce_logfile, - self.max_queue_jobs) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.work_thread.start() - - - - - def merge_cif_files(self,todo): - start_thread = False - if todo == 'merge': - self.update_log.insert('trying to merge %s with ligand restraint files in project directory' %self.second_cif_file) - elif todo == 'restore': - self.update_log.insert('restoring original CIF files') - start_thread = True - - if todo == 'merge': - if os.path.isfile(str(self.second_cif_file)): - self.update_log.insert('checking compound code of second CIF file (%s)' % self.second_cif_file) - self.update_log.insert('Note: LIG and DRG are not allowed!') - import iotbx.cif - cif_model = iotbx.cif.reader(file_path=self.second_cif_file).model() - cif_block = cif_model["comp_list"] - ligID = cif_block["_chem_comp.id"] - self.update_log.insert('found the following compound codes in the supplied CIF file: %s' % str(list(ligID))) - if 'LIG' in list(ligID) or 'DRG' in list(ligID): - self.update_log.error('please change compound code to something other than LIG or DRG') - start_thread = False - else: - start_thread = True - else: - self.update_log.error(XChemToolTips.second_cif_file_not_exists()) - start_thread = False - - if start_thread: - msgBox = QtGui.QMessageBox() - msgBox.setText(XChemToolTips.second_cif_file_info(self.second_cif_file)) - msgBox.addButton(QtGui.QPushButton('OK'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('Cancel'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - start_thread = True - else: - start_thread = False - else: - self.status_bar.showMessage('Error. Please check terminal window for further information') - - tmp = self.db.execute_statement( - "select CrystalName,CompoundCode from mainTable where CrystalName is not '' and CompoundSmiles is not '' and CompoundSmiles is not NULL;") - compound_list = [] - for item in tmp: - xtal = str(item[0]) - compoundID = str(item[1]) - if compoundID == '' or compoundID == 'NULL': - self.update_log.warning('%s: no compound ID in database; skipping...' %xtal) - else: - if str(item[0]) in self.initial_model_dimple_dict: - if self.initial_model_dimple_dict[str(item[0])][0].isChecked(): - self.update_log.warning('%s: %s is flagged for merging' % (xtal, compoundID)) - compound_list.append([xtal, compoundID]) - - if compound_list == []: - self.update_log.error('Either no compound ID information in database or no sample selected!') - start_thread = False - - if start_thread: - - self.explorer_active = 1 - self.work_thread = XChemThread.merge_cif_files(self.initial_model_directory, - self.xce_logfile, - self.second_cif_file, - compound_list, - todo) - self.connect(self.work_thread, QtCore.SIGNAL("update_progress_bar"), self.update_progress_bar) - self.connect(self.work_thread, QtCore.SIGNAL("update_status_bar(QString)"), self.update_status_bar) - self.connect(self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished) - self.connect(self.work_thread, QtCore.SIGNAL("datasource_menu_reload_samples"), - self.datasource_menu_reload_samples) - self.work_thread.start() - - - def update_deposition_table(self): - # check if PanDDA models are ready for deposition - - depositChecks = XChemDeposit.update_deposition_table( - os.path.join(self.database_directory, self.data_source_file)) - - toDeposit, mismatch = depositChecks.PanDDA_models_to_deposit() - - if mismatch != {}: - self.update_log.insert('The following samples contain ligand that are not ready for deposition:') - for entry in mismatch: - self.update_log.insert(entry[0] + ' -> site: ' + entry[1] + ' @ ' + entry[2] + ' => ' + entry[4]) - self.update_log.insert('You need to change this before you can continue!') - return None - - for xtal in toDeposit: - self.db.update_insert_depositTable(xtal, {}) - - def show_html_summary_and_diffraction_image(self): - for key in self.albula_button_dict: - if self.albula_button_dict[key][0] == self.sender(): - print('==> XCE: showing html summary in firefox') - self.show_html_summary_in_firefox(key) - - def need_to_switch_main_tab(self, task_index): - msgBox = QtGui.QMessageBox() - msgBox.setText("Need to switch main tab before you can launch this job") - msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - self.main_tab_widget.setCurrentIndex(task_index) - - def check_write_permissions_of_data_source(self): - write_enabled = True - if not os.access(os.path.join(self.database_directory, self.data_source_file), os.W_OK): - QtGui.QMessageBox.warning(self.window, "Data Source Problem", - '\nData Source is Read-Only\n', - QtGui.QMessageBox.Cancel, QtGui.QMessageBox.NoButton, - QtGui.QMessageBox.NoButton) - write_enabled = False - return write_enabled - - def no_data_source_selected(self): - QtGui.QMessageBox.warning(self.window, "Data Source Problem", - ('Please set or create a data source file\n') + - ('Options:\n') + - ('1. Use an existing file:\n') + - ('- Settings -> Select Data Source File\n') + - ('2. Create a new file\n') + - ('- Data Source -> Create New Data\nSource (SQLite)'), - QtGui.QMessageBox.Cancel, QtGui.QMessageBox.NoButton, - QtGui.QMessageBox.NoButton) - - def update_progress_bar(self, progress): - self.progress_bar.setValue(progress) - - def update_status_bar(self, message): - self.status_bar.showMessage(message) - - def thread_finished(self): - self.explorer_active = 0 - self.update_progress_bar(0) - self.update_status_bar('idle') - - def show_error_dict(self, errorDict): - text = '' - for key in errorDict: - text += '{0!s}:\n'.format(key) - for entry in errorDict[key]: - text += ' - ' + entry + '\n' - msgBox = QtGui.QMessageBox() - msgBox.setText(text) - msgBox.exec_() - - def create_widgets_for_autoprocessing_results_only(self, data_dict): - self.status_bar.showMessage('Building details table for data processing results') - self.data_collection_dict = data_dict - - column_name = ['Program', - 'Resolution\nOverall', - 'Resolution\n[Mn = 2.0]', - 'DataProcessing\nSpaceGroup', - 'Mn\nHigh', - 'Rmerge\nLow', - 'Completeness\nOverall', - 'DataProcessing\nUnitCell', - 'DataProcessing\nRfree', - 'DataProcessing\nScore'] - - # need to do this because db_dict keys are SQLite column names - diffraction_data_column_name = XChemDB.data_source( - os.path.join(self.database_directory, self.data_source_file)).translate_xce_column_list_to_sqlite( - column_name) - - for xtal in sorted(self.data_collection_dict): - if os.path.isfile(os.path.join(self.initial_model_directory, xtal, xtal + '.mtz')): - mtz_already_in_inital_model_directory = True - - # column 2: data collection date - # this one should always be there; it may need updating in case another run appears - # first find latest run - tmp = [] - for entry in self.data_collection_dict[xtal]: - if entry[0] == 'image': - tmp.append([entry[3], datetime.strptime(entry[3], '%Y-%m-%d %H:%M:%S')]) - latest_run = max(tmp, key=lambda x: x[1])[0] - - # first check if it does already exist - if xtal not in self.data_collection_column_three_dict: - # generate all the widgets which can later be appended and add them to the dictionary - data_collection_table = QtGui.QTableWidget() # table with data processing results for each pipeline - selection_changed_by_user = False - self.data_collection_column_three_dict[xtal] = [data_collection_table, selection_changed_by_user] - xtal_in_table = True - else: - data_collection_table = self.data_collection_column_three_dict[xtal][0] - selection_changed_by_user = self.data_collection_column_three_dict[xtal][1] - - data_collection_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - data_collection_table.setColumnCount(len(column_name)) - font = QtGui.QFont() - font.setPointSize(8) - data_collection_table.setFont(font) - data_collection_table.setHorizontalHeaderLabels(column_name) - data_collection_table.horizontalHeader().setFont(font) - data_collection_table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - - ############################################################################# - # crystal images - # first check there are new images that are not displayed yet; i.e. they are not in the self.data_collection_image_dict - if xtal not in self.data_collection_image_dict: - # OK this is the first time - self.data_collection_image_dict[xtal] = [] - - # sort crystal images by timestamp - # reminder: ['image',visit,run,timestamp,image_list,diffraction_image,run_number] - # a) get only image entries from self.data_collection_dict - tmp = [] - for entry in self.data_collection_dict[xtal]: - if entry[0] == 'image': - tmp.append(entry) - - # b) sort by the previously assigned run number - # note: entry[6]==run_number - for entry in sorted(tmp, key=lambda x: x[6]): - run_number = entry[6] - images_already_in_table = False - for image in self.data_collection_image_dict[xtal]: - if run_number == image[0]: - images_already_in_table = True - break - if not images_already_in_table: - # not if there is a run, but images are for whatever reason not present in self.data_collection_dict - # then use image not available from $XChemExplorer_DIR/image/IMAGE_NOT_AVAILABLE.png - # not sure how to do this at the moment; it will probably trigger an error that I can catch - self.data_collection_image_dict[xtal].append([entry[6], entry[1], entry[2], entry[3], entry[5]]) - - ############################################################################# - # initialize dataset_outcome_dict for xtal - if xtal not in self.dataset_outcome_dict: - self.dataset_outcome_dict[xtal] = [] - # dataset outcome buttons - - ############################################################################# - # table for data processing results - # check if results from particular pipeline are already in table; - # not really looking at the table here, but compare it to self.data_collection_table_dict - row_position = data_collection_table.rowCount() - if not xtal in self.data_collection_table_dict: - self.data_collection_table_dict[xtal] = [] - # reminder: ['logfile',visit,run,timestamp,autoproc,file_name,aimless_results,,False] - logfile_list = [] - for entry in self.data_collection_dict[xtal]: - if entry[0] == 'logfile': - logfile_list.append(entry) - for entry in sorted(logfile_list, key=lambda x: x[7]): # sort by aimless_index and so make sure - entry_already_in_table = False # that aimless_index == row - for logfile in self.data_collection_table_dict[xtal]: - if entry[1] == logfile[1] and entry[2] == logfile[2] and entry[3] == logfile[3] and entry[4] == \ - logfile[4]: - entry_already_in_table = True - # might have to update Rfree column - for column, header in enumerate(diffraction_data_column_name): - if header == 'DataProcessing\nRfree': - # entry[7]==aimless_index, i.e. row number - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(db_dict[header[1]])) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - data_collection_table.setItem(entry[7], column, cell_text) - break - break - if not entry_already_in_table: - data_collection_table.insertRow(row_position) - db_dict = entry[6] - for column, header in enumerate(diffraction_data_column_name): - cell_text = QtGui.QTableWidgetItem() - try: - cell_text.setText(str(db_dict[header[1]])) - except KeyError: - # this may happen if not score exists - cell_text.setText('0') - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - data_collection_table.setItem(row_position, column, cell_text) - data_collection_table.setRowHeight(row_position, 20) - row_position += 1 - - self.data_collection_table_dict[xtal].append( - ['logfile', entry[1], entry[2], entry[3], entry[4]]) # 'logfile' is just added to have - # same index numbers between lists - data_collection_table.cellClicked.connect(self.user_update_selected_autoproc_datasets_summary_table) - - # select best resolution file + set data collection outcome - # the assumption is that index in data_collection_dict and row number are identical - # the assumption for data collection outcome is that as long as a logfile is found, it's a success - logfile_found = False - for entry in self.data_collection_dict[xtal]: - if entry[0] == 'logfile': - index = entry[7] - best_file = entry[8] - logfile_found = True - if best_file: - # we change the selection only if the user did not touch it, assuming that he/she knows best - # if not selection_changed_by_user: - data_collection_table.selectRow(index) - - self.populate_datasets_summary_table() - - def find_suitable_reference_file(self, db_dict): - reference_file = [] - dummy = ['...', '', '', '', 0, '0'] - reference_file.append([dummy, 999]) - suitable_reference = [] - for reference in self.reference_file_list: - # first we need one in the same pointgroup - if reference[5] == db_dict['DataProcessingPointGroup']: - try: - difference = math.fabs( - 1 - (float(db_dict['DataProcessingUnitCellVolume']) / float(reference[4]))) * 100 - reference_file.append([reference, difference]) - except ValueError: - continue - return reference_file - - def create_maps_table(self): - column_name = self.db.translate_xce_column_list_to_sqlite(self.maps_table_columns) - - for xtal in sorted(self.xtal_db_dict): - new_xtal = False - db_dict = self.xtal_db_dict[xtal] - if str(db_dict['DataCollectionOutcome']).lower().startswith('success'): - reference_file = self.find_suitable_reference_file(db_dict) - smallest_uc_difference = min(reference_file, key=lambda x: x[1]) - row = self.maps_table.rowCount() - if xtal not in self.initial_model_dimple_dict: - self.maps_table.insertRow(row) - current_row = row - new_xtal = True - else: - for table_row in range(row): - if self.maps_table.item(table_row, 0).text() == xtal: - current_row = table_row - break - for column, header in enumerate(column_name): - if header[0] == 'Sample ID': - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(xtal)) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.maps_table.setItem(current_row, column, cell_text) - elif header[0] == 'Select': - if new_xtal: - run_dimple = QtGui.QCheckBox() - run_dimple.toggle() - self.maps_table.setCellWidget(current_row, column, run_dimple) - run_dimple.setChecked(False) - elif header[0] == 'Reference\nSpaceGroup': - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(smallest_uc_difference[0][1])) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.maps_table.setItem(current_row, column, cell_text) - elif header[0] == 'Difference\nUC Volume (%)': - cell_text = QtGui.QTableWidgetItem() - smallest_uc_difference = min(reference_file, key=lambda x: x[1]) - cell_text.setText(str(round(float(smallest_uc_difference[1]), 1))) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.maps_table.setItem(current_row, column, cell_text) - elif header[0] == 'Reference File': - if new_xtal: - reference_file_selection_combobox = QtGui.QComboBox() - self.populate_reference_combobox(reference_file_selection_combobox) - if float(smallest_uc_difference[1]) < self.allowed_unitcell_difference_percent: - index = reference_file_selection_combobox.findText(str(smallest_uc_difference[0][0]), - QtCore.Qt.MatchFixedString) - reference_file_selection_combobox.setCurrentIndex(index) - else: - reference_file_selection_combobox.setCurrentIndex(0) - self.maps_table.setCellWidget(current_row, column, - reference_file_selection_combobox) - else: - reference_file_selection_combobox = self.initial_model_dimple_dict[xtal][1] - self.populate_reference_combobox(reference_file_selection_combobox) - if float(smallest_uc_difference[1]) < self.allowed_unitcell_difference_percent: - index = reference_file_selection_combobox.findText(str(smallest_uc_difference[0][0]), - QtCore.Qt.MatchFixedString) - reference_file_selection_combobox.setCurrentIndex(index) - else: - reference_file_selection_combobox.setCurrentIndex(0) - else: - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(db_dict[header[1]])) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - if header[0] == 'Dimple\nStatus': - if str(db_dict[header[1]]) == 'running': - cell_text.setBackground(QtGui.QColor(100, 230, 150)) - elif str(db_dict[header[1]]) == 'pending': - cell_text.setBackground(QtGui.QColor(20, 100, 230)) - elif str(db_dict[header[1]]) == 'started': - cell_text.setBackground(QtGui.QColor(230, 240, 110)) - elif str(db_dict[header[1]]) == 'finished': - cell_text.setBackground(QtGui.QColor(255, 255, 255)) - if header[0] == 'Compound\nStatus': - if str(db_dict[header[1]]) == 'running': - cell_text.setBackground(QtGui.QColor(100, 230, 150)) - elif str(db_dict[header[1]]) == 'pending': - cell_text.setBackground(QtGui.QColor(20, 100, 230)) - elif str(db_dict[header[1]]) == 'started': - cell_text.setBackground(QtGui.QColor(230, 240, 110)) - elif str(db_dict[header[1]]) == 'restraints generated': - cell_text.setBackground(QtGui.QColor(255, 255, 255)) - elif str(db_dict[header[1]]) == 'restraints failed': - cell_text.setBackground(QtGui.QColor(255, 0, 0)) - elif str(db_dict[header[1]]) == 'missing smiles': - cell_text.setBackground(QtGui.QColor(240, 150, 20)) - self.maps_table.setItem(current_row, column, cell_text) - if new_xtal: - self.initial_model_dimple_dict[xtal] = [run_dimple, reference_file_selection_combobox] - - def preferences_data_to_copy_combobox_changed(self, i): - text = str(self.preferences_data_to_copy_combobox.currentText()) - for item in self.preferences_data_to_copy: - if item[0] == text: - self.preferences['processed_data_to_copy'] = item[1] - break - - def preferences_selection_mechanism_combobox_changed(self, i): - text = str(self.preferences_selection_mechanism_combobox.currentText()) - self.preferences['dataset_selection_mechanism'] = text - self.update_log.insert('setting datasets selection mechanism to ' + text) - - def preferences_initial_refinement_combobox_changed(self, i): - text = str(self.preferences_initial_refinement_combobox.currentText()) - self.preferences['initial_refinement_pipeline'] = text - self.update_log.insert('setting initial refinement pipeline to ' + text) - - def preferences_restraints_generation_combobox_changed(self): - text = str(self.preferences_restraints_generation_combobox.currentText()) - self.restraints_program = text - self.update_log.insert('will use {0!s} for generation of ligand coordinates and restraints'.format(text)) - - def refinement_outcome_combobox_changed(self): - for xtal in self.refinement_table_dict: - if self.sender() == self.refinement_table_dict[xtal]: - db_dict = {'RefinementOutcome': str(self.sender().currentText())} - self.db.create_or_remove_missing_records_in_depositTable(self.xce_logfile, xtal, 'ligand_bound', - db_dict) - - def get_reference_file_list(self, reference_root): - # check available reference files - reference_file_list = [] - dummy = ['...', '', '', '', 0, '0'] - reference_file_list.append(dummy) - if os.path.isfile(os.path.join(self.reference_directory, reference_root + '.pdb')): - pdb_reference = parse().PDBheader(os.path.join(self.reference_directory, reference_root + '.pdb')) - spg_reference = pdb_reference['SpaceGroup'] - unitcell_reference = pdb_reference['UnitCell'] - lattice_reference = pdb_reference['Lattice'] - unitcell_volume_reference = pdb_reference['UnitCellVolume'] - pointgroup_reference = pdb_reference['PointGroup'] - reference_file_list.append([reference_root, - spg_reference, - unitcell_reference, - lattice_reference, - unitcell_volume_reference, - pointgroup_reference]) - else: - for files in glob.glob(self.reference_directory + '/*'): - if files.endswith('.pdb'): - reference_root = files[files.rfind('/') + 1:files.rfind('.')] - - if os.path.isfile(os.path.join(self.reference_directory, reference_root + '.pdb')): - # reference_file = reference_root + '.pdb' - pdb_reference = parse().PDBheader( - os.path.join(self.reference_directory, reference_root + '.pdb')) - spg_reference = pdb_reference['SpaceGroup'] - unitcell_reference = pdb_reference['UnitCell'] - lattice_reference = pdb_reference['Lattice'] - unitcell_volume_reference = pdb_reference['UnitCellVolume'] - pointgroup_reference = pdb_reference['PointGroup'] - reference_file_list.append([reference_root, - spg_reference, - unitcell_reference, - lattice_reference, - unitcell_volume_reference, - pointgroup_reference]) - for n, file in enumerate(reference_file_list): - self.update_log.insert('reference file {0!s}: {1!s}'.format(n, file)) - return reference_file_list - - def dataset_outcome_combobox_change_outcome(self, text): - outcome = str(text) - xtal = '' - for key in self.dataset_outcome_combobox_dict: - if self.dataset_outcome_combobox_dict[key] == self.sender(): - xtal = key - self.update_log.insert('user changed data collection outcome of {0!s} to {1!s}'.format(xtal, outcome)) - break - self.dataset_outcome_dict[xtal] = outcome - if xtal != '': -# # need to also update if not yet done -# user_already_changed_selection = False -# for n, entry in enumerate(self.data_collection_dict[xtal]): -# if entry[0] == 'user_changed_selection': -# user_already_changed_selection = True -# if entry[0] == 'logfile': -# db_dict = entry[6] -# db_dict['DataCollectionOutcome'] = outcome -# entry[6] = db_dict -# self.data_collection_dict[xtal][n] = entry -# if not user_already_changed_selection: -# self.data_collection_dict[xtal].append(['user_changed_selection']) -# # finally need to update outcome field in data source accordingly - self.update_log.insert('updating dataset outcome in datasource for {0!s}'.format(xtal)) - update_dict = {'DataCollectionOutcome': outcome} - self.db.update_insert_data_source(xtal, update_dict) - - def set_run_dimple_flag(self, state): - if state == QtCore.Qt.Checked: - for key in self.initial_model_dimple_dict: - self.initial_model_dimple_dict[key][0].setChecked(True) - else: - for key in self.initial_model_dimple_dict: - self.initial_model_dimple_dict[key][0].setChecked(False) - - - def show_data_collection_details(self, state): - # first remove currently displayed widget - if self.data_collection_details_currently_on_display is not None: - self.data_collection_details_currently_on_display.hide() - self.data_collection_details_currently_on_display = None - - tmp = [] - allRows = self.datasets_summary_table.rowCount() - for table_row in range(allRows): - tmp.append([self.datasets_summary_table.item(table_row, 0).text(), table_row]) - - for key in self.datasets_summary_dict: - if self.datasets_summary_dict[key][3] == self.sender(): - if self.sender().isChecked(): - for item in tmp: - if item[0] == key: - self.datasets_summary_table.selectRow(item[1]) - self.data_collection_details_currently_on_display = self.data_collection_column_three_dict[key][0] - self.datasets_summarys_vbox_for_details.addWidget( - self.data_collection_details_currently_on_display) - self.data_collection_details_currently_on_display.show() - else: - # un-check all other ones - self.datasets_summary_dict[key][3].setChecked(False) - -# def populate_datasets_summary_table(self): -# self.status_bar.showMessage( -# 'Building summary table for data processing results; be patient this may take a while') -# row = self.datasets_summary_table.rowCount() -# column_name = self.db.translate_xce_column_list_to_sqlite(self.datasets_summary_table_columns) -# -# pinList = self.db.execute_statement( -# "Select CrystalName,PinBarcode,DataCollectionPinBarcode from mainTable where CrystalName is not ''") -# pinDict = {} -# for item in pinList: -# pinDict[str(item[0])] = [str(item[1]), str(item[2])] -# -# for xtal in sorted(self.data_collection_dict): -# new_xtal = False -# if xtal not in self.datasets_summary_dict: -# row = self.datasets_summary_table.rowCount() -# self.datasets_summary_table.insertRow(row) -# self.datasets_summary_dict[xtal] = [] -# new_xtal = True -# -# # check for dataset outcome -# outcome = '' -# logfile_found = False -# too_low_resolution = True -# db_dict = {} -# for entry in self.data_collection_dict[xtal]: -# if entry[0] == 'logfile': -# logfile_found = True -# if entry[8]: # if this was auto-selected best resolution file -# db_dict = entry[6] -# try: -# if float(db_dict['DataProcessingResolutionHigh']) <= float( -# self.acceptable_low_resolution_limit_for_data): -# too_low_resolution = False -# except ValueError: -# pass -# -# try: -# outcome = str(self.db.get_value_from_field(xtal, 'DataCollectionOutcome')[0]) -# except TypeError: -# outcome = 'Failed - unknown' -# self.update_log.insert('cannot find DataCollectionOutcome for {0!s}'.format(xtal)) -# self.dataset_outcome_dict[xtal] = outcome -# -# # find latest run for crystal and diffraction images -# tmp = [] -# for entry in self.data_collection_dict[xtal]: -# if entry[0] == 'image': -# tmp.append([entry, datetime.strptime(entry[3], '%Y-%m-%d %H:%M:%S')]) -# latest_run = max(tmp, key=lambda x: x[1])[0] -# -# new_run_for_exisiting_crystal_or_new_sample = True -# if new_xtal: -# self.datasets_summary_dict[xtal] = [outcome, db_dict, latest_run] -# else: -# # check if newer run appeared -# old_run_timestamp = self.datasets_summary_dict[xtal][2][3] -# new_run_timestamp = latest_run[3] -# if old_run_timestamp == new_run_timestamp: -# new_run_for_exisiting_crystal_or_new_sample = False -# else: -# checkbox_for_details = self.datasets_summary_dict[xtal][3] -# self.datasets_summary_dict[xtal] = [outcome, db_dict, latest_run, checkbox_for_details] -# -# if new_xtal: -# current_row = row -# else: -# allRows = self.datasets_summary_table.rowCount() -# for table_row in range(allRows): -# if self.datasets_summary_table.item(table_row, 0).text() == xtal: -# current_row = table_row -# break -# -# image_number = 0 -# for column, header in enumerate(column_name): -# if header[0] == 'Sample ID': -# cell_text = QtGui.QTableWidgetItem() -# cell_text.setText(str(xtal)) -# cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) -# self.datasets_summary_table.setItem(current_row, column, cell_text) -# elif header[0] == 'DataCollection\nOutcome': -# if new_xtal: -# dataset_outcome_combobox = QtGui.QComboBox() -# for outcomeItem in self.dataset_outcome: -# dataset_outcome_combobox.addItem(outcomeItem) -# self.datasets_summary_table.setCellWidget(current_row, column, dataset_outcome_combobox) -# dataset_outcome_combobox.activated[str].connect(self.dataset_outcome_combobox_change_outcome) -# self.dataset_outcome_combobox_dict[xtal] = dataset_outcome_combobox -# index = self.dataset_outcome_combobox_dict[xtal].findText(str(outcome), QtCore.Qt.MatchFixedString) -# self.dataset_outcome_combobox_dict[xtal].setCurrentIndex(index) -# continue -# -# elif header[0].startswith('img'): -# if new_run_for_exisiting_crystal_or_new_sample: -# img = latest_run[4] -# pixmap = QtGui.QPixmap() -# # can do this (img[image_number][1]) because made sure in the threading module -# # that there are always exactly 5 images in there -# pixmap.loadFromData(base64.b64decode(img[image_number][1])) -# image = QtGui.QLabel() -# image.resize(128, 80) -# image.setPixmap(pixmap.scaled(image.size(), QtCore.Qt.KeepAspectRatio)) -# self.datasets_summary_table.setCellWidget(current_row, column, image) -# image_number += 1 -# -# elif header[0].startswith('Show Diffraction\nImage'): -# if new_run_for_exisiting_crystal_or_new_sample: -# diffraction_image = latest_run[5] -# diffraction_image_name = diffraction_image[diffraction_image.rfind('/') + 1:] -# try: # need to try because older pkl file may not have this item in list -# html_summary = latest_run[7] -# except IndexError: -# html_summary = '' -# if new_xtal: -# start_albula_button = QtGui.QPushButton('Show: \n' + diffraction_image_name) -# start_albula_button.clicked.connect(self.show_html_summary_and_diffraction_image) -# self.albula_button_dict[xtal] = [start_albula_button, diffraction_image, html_summary] -# self.datasets_summary_table.setCellWidget(current_row, column, start_albula_button) -# else: -# self.albula_button_dict[xtal][1] = diffraction_image -# elif header[0].startswith('Show\nDetails'): -# if new_xtal: -# show_data_collection_details_checkbox = QtGui.QCheckBox() -# show_data_collection_details_checkbox.toggle() -# show_data_collection_details_checkbox.setChecked(False) -# show_data_collection_details_checkbox.stateChanged.connect(self.show_data_collection_details) -# self.datasets_summary_table.setCellWidget(current_row, column, -# show_data_collection_details_checkbox) -# self.datasets_summary_dict[xtal].append(show_data_collection_details_checkbox) -# elif header[0].startswith('SoakDB\nBarcode') or header[0].startswith('GDA\nBarcode'): -# if new_xtal: -# cell_text = QtGui.QTableWidgetItem() -# if xtal in pinDict: -# if header[0].startswith('SoakDB\nBarcode'): -# cell_text.setText(str(pinDict[xtal][0])) -# elif header[0].startswith('GDA\nBarcode'): -# cell_text.setText(str(pinDict[xtal][1])) -# if pinDict[xtal][0] == 'NULL' or pinDict[xtal][1] == 'NULL': -# cell_text.setBackground(QtGui.QColor(255, 215, 0)) -# elif pinDict[xtal][0] != pinDict[xtal][1]: -# cell_text.setBackground(QtGui.QColor(255, 0, 0)) -# else: -# cell_text.setText('') -# cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) -# self.datasets_summary_table.setItem(current_row, column, cell_text) -# else: -# cell_text = QtGui.QTableWidgetItem() -# # in case data collection failed for whatever reason -# if logfile_found: -# try: -# cell_text.setText(str(db_dict[header[1]])) -# except KeyError: # older pkl files may not have all the columns -# cell_text.setText('n/a') -# else: -# if header[0].startswith('Resolution\n[Mn = 1.5]'): -# cell_text.setText('999') -# elif header[0].startswith('DataProcessing\nRfree'): -# cell_text.setText('999') -# elif header[0].startswith('Rmerge\nLow'): -# cell_text.setText('999') -# else: -# cell_text.setText('') -# cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) -# self.datasets_summary_table.setItem(current_row, column, cell_text) -# -# row += 1 -# -# self.datasets_summary_table.resizeRowsToContents() -# self.datasets_summary_table.resizeColumnsToContents() -# -# self.status_bar.showMessage('updating Overview table') -# -# self.status_bar.showMessage('idle') -# -# self.save_files_to_initial_model_folder() -# - - ################################################################################################################ - # - # - # - # => new data collection summary table - # > start - - def get_sample_list_from_table(self,table): - sampleList = [] - allRows = table.rowCount() - for row in xrange(0, allRows): - sample_id = str(table.item(row, 0).text()) - sampleList.append(sample_id) - return sorted(sampleList) - - def get_row_of_sample_in_table(self,table,xtal): - allRows = table.rowCount() - sampleRow = allRows - for n,row in enumerate(xrange(0, allRows)): - sample_id = str(table.item(row, 0).text()) - if sample_id == xtal: - sampleRow = n - break - return sampleRow - - def update_row_in_table(self,sample,row,db_dict,table,columns_to_show): - xtal = str(sample) - column_name = self.db.translate_xce_column_list_to_sqlite(columns_to_show) - - for column, header in enumerate(column_name): - - if header[0] == 'Sample ID': - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(xtal)) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - table.setItem(row, column, cell_text) - - elif header[0] == 'DataCollection\nOutcome': - if xtal not in self.dataset_outcome_combobox_dict: - dataset_outcome_combobox = QtGui.QComboBox() - for outcomeItem in self.dataset_outcome: - dataset_outcome_combobox.addItem(outcomeItem) - dataset_outcome_combobox.activated[str].connect(self.dataset_outcome_combobox_change_outcome) - self.dataset_outcome_combobox_dict[xtal] = dataset_outcome_combobox - table.setCellWidget(row, column, dataset_outcome_combobox) - index = self.dataset_outcome_combobox_dict[xtal].findText(str(db_dict['DataCollectionOutcome']), QtCore.Qt.MatchFixedString) - self.dataset_outcome_combobox_dict[xtal].setCurrentIndex(index) - - elif header[0].startswith('img'): - if os.path.isfile(db_dict[header[1]]): - pixmap = QtGui.QPixmap(db_dict[header[1]]) - else: - pixmap = QtGui.QPixmap( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'IMAGE_NOT_AVAILABLE.png')) - image = QtGui.QLabel() - image.resize(128, 80) - image.setPixmap(pixmap.scaled(image.size(), QtCore.Qt.KeepAspectRatio)) - table.setCellWidget(row, column, image) - - elif header[0] == 'Select': - checkbox = QtGui.QCheckBox() - checkbox.toggle() - if table == self.deposition_table_apo: - if xtal not in self.deposition_table_apo_dict: - self.deposition_table_apo_dict[xtal] = checkbox - if table == self.deposition_table_bound: - if xtal not in self.deposition_table_bound_dict: - self.deposition_table_bound_dict[xtal] = checkbox - table.setCellWidget(row, column, checkbox) - checkbox.setChecked(False) - - #elif header[0].startswith('SoakDB\nBarcode') or header[0].startswith('GDA\nBarcode'): - # if new_xtal: - # cell_text = QtGui.QTableWidgetItem() - # if xtal in pinDict: - # if header[0].startswith('SoakDB\nBarcode'): - # cell_text.setText(str(pinDict[xtal][0])) - # elif header[0].startswith('GDA\nBarcode'): - # cell_text.setText(str(pinDict[xtal][1])) - # if pinDict[xtal][0] == 'NULL' or pinDict[xtal][1] == 'NULL': - # cell_text.setBackground(QtGui.QColor(255, 215, 0)) - # elif pinDict[xtal][0] != pinDict[xtal][1]: - # cell_text.setBackground(QtGui.QColor(255, 0, 0)) - # else: - # cell_text.setText('') - # cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - # self.datasets_summary_table.setItem(current_row, column, cell_text) - else: - cell_text = QtGui.QTableWidgetItem() - # in case data collection failed for whatever reason - try: - cell_text.setText(str(db_dict[header[1]])) - except KeyError: # older pkl files may not have all the columns - cell_text.setText('n/a') - # else: - # if header[0].startswith('Resolution\n[Mn = 1.5]'): - # cell_text.setText('999') - # elif header[0].startswith('DataProcessing\nRfree'): - # cell_text.setText('999') - # elif header[0].startswith('Rmerge\nLow'): - # cell_text.setText('999') - # else: - # cell_text.setText('') - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - table.setItem(row, column, cell_text) - - - def populate_datasets_summary_table_NEW(self): - self.status_bar.showMessage( - 'Building summary table for data processing results; be patient this may take a while') - - # get information about all samples collected during the current visit - visit, beamline = XChemMain.getVisitAndBeamline(self.beamline_directory) - if self.read_agamemnon.isChecked(): - visit = [] - for v in glob.glob(os.path.join(self.beamline_directory[:self.beamline_directory.rfind('-') + 1] + '*')): - visit.append(v[v.rfind('/')+1:]) - - self.update_log.insert('reading information about collected crystals from database...') - collectedXtalsDict = self.db.xtals_collected_during_visit_as_dict(visit) - - # instead of using dictionaries, query table of which crystals are in table - samples_in_table = self.get_sample_list_from_table(self.datasets_summary_table) - for xtal in sorted(collectedXtalsDict): - if xtal not in samples_in_table: - row = self.datasets_summary_table.rowCount() - self.datasets_summary_table.insertRow(row) - else: - row = self.get_row_of_sample_in_table(self.datasets_summary_table,xtal) - db_dict = collectedXtalsDict[xtal] - self.update_row_in_table(xtal, row, db_dict, self.datasets_summary_table, - self.datasets_summary_table_columns) - - self.datasets_summary_table.resizeRowsToContents() - self.datasets_summary_table.resizeColumnsToContents() - - self.status_bar.showMessage('updating Overview table') - - self.status_bar.showMessage('idle') - - - def get_selected_row(self,table): - indexes = table.selectionModel().selectedRows() - for index in sorted(indexes): - selected_row = index.row() - return selected_row - - def show_results_from_all_pipelines(self): - selected_row=self.get_selected_row(self.datasets_summary_table) - xtal = self.datasets_summary_table.item(selected_row, 0).text() - # get details of currently selected autoprocessing result - selectedResultDict = self.db.get_db_dict_for_sample(xtal) - - dbList=self.db.all_autoprocessing_results_for_xtal_as_dict(xtal) - - self.make_data_collection_table() - self.msgBox = QtGui.QMessageBox() # needs to be created here, otherwise the cellClicked function - # will reference it before it exists - for db_dict in dbList: - if str(db_dict['DataProcessingSpaceGroup']).lower() == 'null' or str(db_dict['DataProcessingSpaceGroup']).lower() == 'none': - continue - row = self.data_collection_table.rowCount() - self.data_collection_table.insertRow(row) - self.update_row_in_table(xtal, row, db_dict, self.data_collection_table, self.data_collection_table_columns) - if selectedResultDict['DataCollectionVisit'] == db_dict['DataCollectionVisit'] \ - and selectedResultDict['DataCollectionRun'] == db_dict['DataCollectionRun'] \ - and selectedResultDict['DataProcessingProgram'] == db_dict['DataProcessingProgram']: - self.current_row = row - self.data_collection_table.selectRow(row) - self.data_collection_table.cellClicked.connect(self.select_different_autoprocessing_result) - self.data_collection_table_popup() - - def make_data_collection_table(self): - # this creates a new table widget every time - # more elegant would be to delete or reset an existing widget... - self.data_collection_table = QtGui.QTableWidget() - self.data_collection_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.data_collection_table.setColumnCount(len(self.data_collection_table_columns)) - font = QtGui.QFont() - font.setPointSize(8) - self.data_collection_table.setFont(font) - self.data_collection_table.setHorizontalHeaderLabels(self.data_collection_table_columns) - self.data_collection_table.horizontalHeader().setFont(font) - self.data_collection_table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - - def data_collection_table_popup(self): -# self.msgBox = QtGui.QMessageBox() - msgBoxLayout = self.msgBox.layout() - qWid = QtGui.QWidget() - qWid.setFixedWidth(3000) - qWid.setFixedHeight(500) - vbox = QtGui.QVBoxLayout() - vbox.addWidget(self.data_collection_table) - qWid.setLayout(vbox) -# msgBoxLayout.addLayout(vbox, 0, 0) - msgBoxLayout.addWidget(qWid) - self.msgBox.addButton(QtGui.QPushButton('Cancel'), QtGui.QMessageBox.RejectRole) - self.msgBox.resize(1000,200) - self.msgBox.exec_(); - - def select_different_autoprocessing_result(self): - selected_row=self.get_selected_row(self.data_collection_table) - if selected_row != self.current_row: - xtal = self.data_collection_table.item(selected_row, 0).text() - visit = self.data_collection_table.item(selected_row, 1).text() - run = self.data_collection_table.item(selected_row, 2).text() - autoproc = self.data_collection_table.item(selected_row, 3).text() - # get db_dict from collectionTable for visit, run, autoproc - dbDict = self.db.get_db_dict_for_visit_run_autoproc(xtal,visit,run,autoproc) - dbDict['DataProcessingAutoAssigned'] = 'False' - self.update_log.insert('%s: changing selected autoprocessing result to %s %s %s' %(xtal,visit,run,autoproc)) - # xtal is QString -> str(xtal) - XChemMain.linkAutoProcessingResult(str(xtal), dbDict, self.initial_model_directory,self.xce_logfile) - self.update_log.insert('%s: updating row in Datasets table' %xtal) - self.db.update_data_source(str(xtal),dbDict) - self.update_log.insert('%s: getting updated information from DB mainTable' %xtal) - dbDict = self.db.get_db_dict_for_sample(xtal) - row = self.get_row_of_sample_in_table(self.datasets_summary_table,xtal) - self.update_row_in_table(xtal, row, dbDict, self.datasets_summary_table, - self.datasets_summary_table_columns) - else: - print 'nothing to change' - self.msgBox.done(1) - - - - # < end - ################################################################################################################# - - - - - - - - - - - - - def update_outcome_datasets_summary_table(self, sample, outcome): - rows_in_table = self.datasets_summary_table.rowCount() - for row in range(rows_in_table): - if self.datasets_summary_table.item(row, 0).text() == sample: - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(outcome) - self.datasets_summary_table.setItem(row, 3, cell_text) - - def user_update_selected_autoproc_datasets_summary_table(self): - for key in self.data_collection_column_three_dict: - if self.data_collection_column_three_dict[key][0] == self.sender(): - dbTmp = self.xtal_db_dict[key] - stage = dbTmp['RefinementOutcome'].split()[0] - print('===>', key, stage) - if int(stage) > 2: - msgBox = QtGui.QMessageBox() - msgBox.setText( - "*** WARNING ***\n%s is currently %s\nIt will disappear from the Refinement table,\n" - "when you refresh it next time.\nDo you want to continue?" % ( - key, dbTmp['RefinementOutcome'])) - msgBox.addButton(QtGui.QPushButton('No'), QtGui.QMessageBox.YesRole) - msgBox.addButton(QtGui.QPushButton('Yes'), QtGui.QMessageBox.RejectRole) - reply = msgBox.exec_(); - if reply == 0: - self.update_log.insert('will not change data processing selection') - # restore previous selection - for n, entry in enumerate(self.data_collection_dict[key]): - print('==>', n) - if entry[0] == 'logfile': - if entry[8]: - print('===> found:', n) - self.data_collection_column_three_dict[key][0].selectRow(n) - break - - indexes = self.sender().selectionModel().selectedRows() - selected_processing_result = 1000000 - for index in sorted(indexes): - selected_processing_result = index.row() - # the user changed the selection, i.e. no automated selection will update it - self.update_log.insert('user changed selection') - self.data_collection_column_three_dict[key][1] = True - # need to also update if not yet done - user_already_changed_selection = False - for n, entry in enumerate(self.data_collection_dict[key]): - if entry[0] == 'user_changed_selection': - user_already_changed_selection = True - if entry[0] == 'logfile': - db_dict = entry[6] - db_dict['DataProcessingAutoAssigned'] = 'False' - if entry[7] == selected_processing_result: - db_dict_current = entry[6] - program = db_dict['DataProcessingProgram'] - visit = db_dict['DataCollectionVisit'] - run = db_dict['DataCollectionRun'] - self.update_log.insert( - 'user changed data processing files for {0!s} to visit={1!s}, ' - 'run={2!s}, program={3!s}'.format(key, visit, run, program)) - # update datasource - self.update_log.insert('updating datasource...') - self.update_data_source(key, db_dict) - entry[8] = True - else: - entry[8] = False - - entry[6] = db_dict - self.data_collection_dict[key][n] = entry - if not user_already_changed_selection: - self.data_collection_dict[key].append(['user_changed_selection']) - XChemMain.change_links_to_selected_data_collection_outcome(key, self.data_collection_dict, - self.data_collection_column_three_dict, - self.dataset_outcome_dict, - self.initial_model_directory, - os.path.join(self.database_directory, - self.data_source_file), - self.xce_logfile) - - # update 'Datasets' table - column_name = XChemDB.data_source( - os.path.join(self.database_directory, self.data_source_file)).translate_xce_column_list_to_sqlite( - self.datasets_summary_table_columns) - rows_in_table = self.datasets_summary_table.rowCount() - for row in range(rows_in_table): - if self.datasets_summary_table.item(row, 0).text() == key: - for column, header in enumerate(column_name): - if header[0] == 'Sample ID': - continue - elif header[0] == 'DataCollection\nOutcome': - continue - elif header[0].startswith('img'): - continue - elif header[0].startswith('Show'): - continue - else: - cell_text = QtGui.QTableWidgetItem() - try: - cell_text.setText(str(db_dict_current[header[1]])) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.datasets_summary_table.setItem(row, column, cell_text) - except KeyError: - pass - - def update_selected_autoproc_datasets_summary_table(self): - for key in self.data_collection_column_three_dict: - if self.data_collection_column_three_dict[key][0] == self.sender(): - sample = key - break - indexes = self.sender().selectionModel().selectedRows() - for index in sorted(indexes): - selected_processing_result = index.row() - - for n, entry in enumerate(self.data_collection_dict[sample]): - if entry[0] == 'logfile': - if entry[7] == selected_processing_result: - db_dict = entry[6] - program = db_dict['DataProcessingProgram'] - visit = db_dict['DataCollectionVisit'] - run = db_dict['DataCollectionRun'] - self.update_log.insert( - 'user changed data processing files for {0!s} to visit={1!s}, run={2!s}, program={3!s}'.format( - sample, visit, run, program)) - # update datasource - self.update_log.insert('updating datasource...') - self.update_data_source(sample, db_dict) - entry[8] = True - else: - entry[8] = False - self.data_collection_dict[sample][n] = entry - - # update 'Datasets' table - column_name = XChemDB.data_source( - os.path.join(self.database_directory, self.data_source_file)).translate_xce_column_list_to_sqlite( - self.datasets_summary_table_columns) - rows_in_table = self.datasets_summary_table.rowCount() - for row in range(rows_in_table): - if self.datasets_summary_table.item(row, 0).text() == sample: - for column, header in enumerate(column_name): - if header[0] == 'Sample ID': - continue - elif header[0] == 'DataCollection\nOutcome': - continue - elif header[0].startswith('img'): - continue - elif header[0].startswith('Show'): - continue - else: - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(db_dict[header[1]])) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.datasets_summary_table.setItem(row, column, cell_text) - - def populate_and_update_datasource_table(self): - self.overview_datasource_table.setColumnCount(len(self.overview_datasource_table_columns)) - - # first get a list of all the samples that are already in the table and which will be updated - samples_in_table = [] - current_row = self.overview_datasource_table.rowCount() - for row in range(current_row): - sampleID = str(self.overview_datasource_table.item(row, 0).text()) # this must be the case - samples_in_table.append(sampleID) - - columns_to_show = self.get_columns_to_show(self.overview_datasource_table_columns) - n_rows = self.get_rows_with_sample_id_not_null_from_datasource() - sample_id_column = self.get_columns_to_show(['Sample ID']) - - for row in self.data: - if str(row[sample_id_column[0]]).lower() == 'none' or str(row[sample_id_column[0]]).replace(' ', '') == '': - # do not show rows where sampleID is null - continue - else: - if not str(row[sample_id_column[0]]) in samples_in_table: - # insert row, this is a new sample - x = self.overview_datasource_table.rowCount() - self.overview_datasource_table.insertRow(x) - else: - # find row of this sample in data_source_table - for present_rows in range(self.overview_datasource_table.rowCount()): - if str(row[sample_id_column[0]]) == str( - self.overview_datasource_table.item(present_rows, 0).text()): - x = present_rows - break - for y, item in enumerate(columns_to_show): - cell_text = QtGui.QTableWidgetItem() - if row[item] is None: - cell_text.setText('') - else: - cell_text.setText(str(row[item])) - if self.overview_datasource_table_columns[y] == 'Sample ID': # assumption is that column 0 is always sampleID - cell_text.setFlags(QtCore.Qt.ItemIsEnabled) # and this field cannot be changed - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.overview_datasource_table.setItem(x, y, cell_text) - self.overview_datasource_table.setHorizontalHeaderLabels(self.overview_datasource_table_columns) - - def kill_other_pandda_options(self): - for i in range(0, self.pandda_analyse_data_table.rowCount()): - checkbox1 = self.pandda_analyse_data_table.cellWidget(i,6) - checkbox2 = self.pandda_analyse_data_table.cellWidget(i,7) - checkbox3 = self.pandda_analyse_data_table.cellWidget(i,8) - if checkbox1.isChecked(): - checkbox2.setChecked(False) - checkbox3.setChecked(False) - if checkbox1.isChecked() and checkbox2.isChecked() or checkbox3.isChecked(): - checkbox1.setChecked(False) - if checkbox2.isChecked() or checkbox3.isChecked(): - checkbox1.setChecked(False) - - def populate_pandda_analyse_input_table(self): - - column_name = self.db.translate_xce_column_list_to_sqlite(self.pandda_table_columns) - print(column_name) - for xtal in sorted(self.xtal_db_dict): - new_xtal = False - db_dict = self.xtal_db_dict[xtal] - if os.path.isfile(db_dict['DimplePathToPDB']): - row = self.pandda_analyse_data_table.rowCount() - if xtal not in self.pandda_analyse_input_table_dict: - self.pandda_analyse_data_table.insertRow(row) - current_row = row - new_xtal = True - else: - for table_row in range(row): - if self.pandda_analyse_data_table.item(table_row, 0).text() == xtal: - current_row = table_row - break - for column, header in enumerate(column_name): - if header[0]=='Exclude': - deselect_button = QtGui.QCheckBox() - deselect_button.stateChanged.connect(self.kill_other_pandda_options) - self.pandda_analyse_data_table.setCellWidget(current_row, column, deselect_button) - - elif header[0]=='Ignore': - deselect_button = QtGui.QCheckBox() - deselect_button.stateChanged.connect(self.kill_other_pandda_options) - self.pandda_analyse_data_table.setCellWidget(current_row, column, deselect_button) - - elif header[0] == 'Sample ID': - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(xtal)) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.pandda_analyse_data_table.setItem(current_row, column, cell_text) - else: - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(db_dict[header[1]])) - if header[0] == 'PanDDA\nStatus': - if str(db_dict[header[1]]) == 'running': - cell_text.setBackground(QtGui.QColor(100, 230, 150)) - elif str(db_dict[header[1]]) == 'pending': - cell_text.setBackground(QtGui.QColor(20, 100, 230)) - elif str(db_dict[header[1]]) == 'started': - cell_text.setBackground(QtGui.QColor(230, 240, 110)) - elif str(db_dict[header[1]]) == 'finished': - cell_text.setBackground(QtGui.QColor(255, 255, 255)) - elif 'problem' in str(db_dict[header[1]]): - cell_text.setBackground(QtGui.QColor(255, 0, 0)) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.pandda_analyse_data_table.setItem(current_row, column, cell_text) - if new_xtal: - self.pandda_analyse_input_table_dict[xtal] = [] - - def select_sample_for_pandda(self, option): - indexes = self.pandda_analyse_data_table.selectionModel().selectedRows() - if option == 'deselect': - for index in sorted(indexes): - self.pandda_analyse_data_table.cellWidget(index.row(), 6).setChecked(False) - self.pandda_analyse_data_table.cellWidget(index.row(), 7).setChecked(False) - self.pandda_analyse_data_table.cellWidget(index.row(), 8).setChecked(False) - else: - for index in sorted(indexes): - self.pandda_analyse_data_table.cellWidget(index.row(), 6).setChecked(False) - self.pandda_analyse_data_table.cellWidget(index.row(), 7).setChecked(False) - self.pandda_analyse_data_table.cellWidget(index.row(), 8).setChecked(False) - if option =='ignore': - checkbox = self.pandda_analyse_data_table.cellWidget(index.row(), 6) - if option == 'char': - checkbox = self.pandda_analyse_data_table.cellWidget(index.row(), 7) - if option == 'zmap': - checkbox = self.pandda_analyse_data_table.cellWidget(index.row(), 8) - - checkbox.setChecked(True) - self.kill_other_pandda_options() - - def populate_and_update_refinement_table(self): - - panddaList = self.db.execute_statement( - "select CrystalName,PANDDA_site_index,PANDDA_site_name,RefinementOutcome " - "from panddaTable where CrystalName is not '' and PANDDA_site_ligand_placed is 'True';") - panddaDict = {} - for item in panddaList: - if str(item[0]) not in panddaDict: - panddaDict[str(item[0])] = [] - panddaDict[str(item[0])].append([str(item[1]), str(item[2]), str(item[3])]) - - column_name = self.db.translate_xce_column_list_to_sqlite(self.refinement_table_columns) - for xtal in sorted(self.xtal_db_dict): - new_xtal = False - db_dict = self.xtal_db_dict[xtal] - try: - stage = int(str(db_dict['RefinementOutcome']).split()[0]) - refinementStage = db_dict['RefinementOutcome'] - except ValueError: - stage = 0 - except IndexError: - stage = 0 - - if stage >= 3: - row = self.refinement_table.rowCount() - if xtal not in self.refinement_table_dict: - self.refinement_table.insertRow(row) - current_row = row - new_xtal = True - else: - for table_row in range(row): - if self.refinement_table.item(table_row, 0).text() == xtal: - current_row = table_row - break - for column, header in enumerate(column_name): - if header[0] == 'Sample ID': - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(xtal)) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.refinement_table.setItem(current_row, column, cell_text) - - elif header[0] == 'Refinement\nOutcome': - if new_xtal: - refinement_outcome_combobox = QtGui.QComboBox() - self.populate_refinement_outcome_combobox(refinement_outcome_combobox) - self.refinement_table.setCellWidget(current_row, column, refinement_outcome_combobox) - else: - refinement_outcome_combobox = self.refinement_table_dict[xtal] - index = refinement_outcome_combobox.findText(refinementStage, QtCore.Qt.MatchFixedString) - refinement_outcome_combobox.setCurrentIndex(index) - refinement_outcome_combobox.currentIndexChanged.connect( - self.refinement_outcome_combobox_changed) - - elif header[0] == 'PanDDA site details': - try: - panddaDict[xtal].insert(0, ['Index', 'Name', 'Status']) - outerFrame = QtGui.QFrame() - outerFrame.setFrameShape(QtGui.QFrame.Box) - grid = QtGui.QGridLayout() - for y, entry in enumerate(panddaDict[xtal]): - for x, info in enumerate(entry): - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.Box) - vbox = QtGui.QVBoxLayout() - vbox.addWidget(QtGui.QLabel(str(entry[x]))) - frame.setLayout(vbox) - grid.addWidget(frame, y, x) - outerFrame.setLayout(grid) - self.refinement_table.setCellWidget(current_row, column, outerFrame) - except KeyError: - cell_text = QtGui.QTableWidgetItem() - cell_text.setText('*** N/A ***') - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.refinement_table.setItem(current_row, column, cell_text) - else: - cell_text = QtGui.QTableWidgetItem() - cell_text.setText(str(db_dict[header[1]])) - if header[0] == 'Refinement\nStatus': - if str(db_dict[header[1]]) == 'running': - cell_text.setBackground(QtGui.QColor(100, 230, 150)) - elif str(db_dict[header[1]]) == 'pending': - cell_text.setBackground(QtGui.QColor(20, 100, 230)) - elif str(db_dict[header[1]]) == 'started': - cell_text.setBackground(QtGui.QColor(230, 240, 110)) - elif str(db_dict[header[1]]) == 'finished': - cell_text.setBackground(QtGui.QColor(255, 255, 255)) - elif 'problem' in str(db_dict[header[1]]): - cell_text.setBackground(QtGui.QColor(255, 0, 0)) - cell_text.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter) - self.refinement_table.setItem(current_row, column, cell_text) - if new_xtal: - self.refinement_table_dict[xtal] = refinement_outcome_combobox - - self.refinement_table.resizeColumnsToContents() - self.refinement_table.resizeRowsToContents() - - def get_columns_to_show(self, column_list): - # maybe I coded some garbage before, but I need to find out which column name in the - # data source corresponds to the actually displayed column name in the table - # reason being that the unique column ID for DB may not be nice to look at - columns_to_show = [] - for column in column_list: - # first find out what the column name in the header is: - column_name = '' - for name in self.all_columns_in_data_source: - if column == name[1]: - column_name = name[0] - for n, all_column in enumerate(self.header): - if column_name == all_column: - columns_to_show.append(n) - break - return columns_to_show - - def get_rows_with_sample_id_not_null_from_datasource(self): - sample_id_column = self.get_columns_to_show(['Sample ID']) - n_rows = 0 - for row in self.data: - if not str(row[sample_id_column[0]]).lower() != 'none' or not str(row[sample_id_column[0]]).replace \ - (' ', '') == '': - n_rows += 1 - return n_rows - - def update_data_source(self, sample, db_dict): - data_source = XChemDB.data_source(os.path.join(self.database_directory, self.data_source_file)) - - def quit_xce(self): - # save pkl file - if self.data_collection_dict != {}: - if os.path.isfile(self.datasets_summary_file): - self.update_log.insert('saving results to PKL file') - pickle.dump(self.data_collection_dict, open(self.datasets_summary_file, 'wb')) - self.update_log.insert('quitting XCE... bye,bye!') - QtGui.qApp.quit() - - -if __name__ == "__main__": - app = XChemExplorer(sys.argv[1:]) - - -# "Debugging is twice as hard as writing the code in the first -# place. Therefore, if you write the code as cleverly as -# possible, you are, by definition, not smart enough to debug it." -# -- Brian W. Kernighan -# ^^ Who did this? :P diff --git a/XChemExplorer_dls b/XChemExplorer_dls new file mode 100755 index 00000000..888b38ed --- /dev/null +++ b/XChemExplorer_dls @@ -0,0 +1,11 @@ +#!/bin/bash + +module load buster/20240123 +module load phenix/1.20 +module load ccp4/7.1.018 + +export BDG_TOOL_MOGUL="/dls_sw/apps/CSDS/2024.1.0/ccdc-software/mogul/bin/mogul" +export XChemExplorer_DIR=$(readlink -e $0 | xargs dirname) +export LD_PRELOAD="/usr/lib64/libfreetype.so:${LD_PRELOAD}" + +ccp4-python $XChemExplorer_DIR/launch.py diff --git a/XChemExplorer_dmd.sh b/XChemExplorer_dmd.sh deleted file mode 100755 index 80167bfe..00000000 --- a/XChemExplorer_dmd.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -export XChemExplorer_DIR="/dls/science/groups/i04-1/software/XChemExplorer_new/XChemExplorer" -source $XChemExplorer_DIR/setup-scripts/xce.setup-sh -module unload ccp4 -source /dls/science/groups/i04-1/software/pandda_0.2.12/ccp4/ccp4-7.0/bin/ccp4.setup-sh - -ccp4-python $XChemExplorer_DIR/XChemExplorer.py diff --git a/XChemExplorer_local.sh b/XChemExplorer_local.sh deleted file mode 100755 index 6cb172d7..00000000 --- a/XChemExplorer_local.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -export XChemExplorer_DIR=$( dirname "${BASH_SOURCE[0]}" ) -echo $XChemExplorer_DIR - -source $XChemExplorer_DIR/setup-scripts/xce.setup-sh -module unload ccp4 -source $XChemExplorer_DIR/../ccp4/bin/ccp4.setup-sh - -ccp4-python $XChemExplorer_DIR/XChemExplorer.py diff --git a/compile_test.py b/compile_test.py deleted file mode 100755 index 82081743..00000000 --- a/compile_test.py +++ /dev/null @@ -1,19 +0,0 @@ -import os, sys - -# set XCE environment variables -os.environ['XChemExplorer_DIR'] = os.path.join(os.getcwd(), 'XChemExplorer/') - -print('XCE path = ' + os.environ['XChemExplorer_DIR']) - -# Append all directories to path -sys.path.append(os.environ['XChemExplorer_DIR']) - -# print PATH to check -print('Current path:- ') -for p in sys.path: - print(p) - -# try to import all of XCE stuff -from XChemExplorer import * - -print('Successfully imported XCE... compile was succesful') diff --git a/coot/XChemCoot.py b/coot/XChemCoot.py new file mode 100755 index 00000000..d4b8a97a --- /dev/null +++ b/coot/XChemCoot.py @@ -0,0 +1,1678 @@ +import sys +import glob +import os +import pickle + +import coot +import coot_gui +import coot_utils +import gobject +import gtk +from matplotlib.figure import Figure + +# had to adapt the original coot_utils.py file +# otherwise unable to import the original file without complaints about missing modules +# etc. +# modified file is now in $XChemExplorer_DIR/lib + + +class GUI(object): + """ + main class which opens the actual GUI + """ + + def __init__(self): + ################################################################################ + # read in settings file from XChemExplorer to set the relevant paths + self.settings = pickle.load(open(".xce_settings.pkl", "rb")) + + self.database_directory = self.settings["database_directory"] + self.xce_logfile = self.settings["xce_logfile"] + self.Logfile = XChemLog.updateLog(self.xce_logfile) + self.Logfile.insert("==> COOT: starting coot plugin...") + self.data_source = self.settings["data_source"] + self.db = XChemDB.data_source(self.data_source) + + print(self.settings) + + # checking for external software packages + self.external_software = XChemUtils.external_software(self.xce_logfile).check() + + self.selection_criteria = [ + "0 - All Datasets", + "1 - Analysis Pending", + "2 - PANDDA model", + "3 - In Refinement", + "4 - CompChem ready", + "5 - Deposition ready", + "6 - Deposited", + "7 - Analysed & Rejected", + ] + + self.experiment_stage = [ + ["Review PANDDA export", "2 - PANDDA model", 65000, 0, 0], + ["In Refinement", "3 - In Refinement", 65000, 0, 0], + ["Comp Chem Ready!", "4 - CompChem ready", 65000, 0, 0], + ["Ready for Deposition!", "5 - Deposition ready", 65000, 0, 0], + ["In PDB", "6 - Deposited", 65000, 0, 0], + ["Analysed & Rejected", "7 - Analysed & Rejected", 65000, 0, 0], + ] + + self.ligand_confidence_category = [ + "0 - no ligand present", + "1 - Low Confidence", + "2 - Correct ligand, weak density", + "3 - Clear density, unexpected ligand", + "4 - High Confidence", + ] + + # this decides which samples will be looked at + self.selection_mode = "" + self.pandda_index = -1 # refers to the number of sites + self.site_index = "0" + self.event_index = "0" + + # the Folder is kind of a legacy thing because my inital idea was to have + # separate folders for Data Processing and Refinement + self.project_directory = self.settings["initial_model_directory"] + self.Serial = 0 + self.panddaSerial = 0 + self.Refine = None + self.index = -1 + self.Todo = [] + self.siteDict = {} + + self.xtalID = "" + self.compoundID = "" + self.ground_state_mean_map = "" + self.spider_plot = "" + self.ligand_confidence = "" + self.refinementProtocol = "pandda_refmac" + + self.pdb_style = "refine.pdb" + self.mtz_style = "refine.mtz" + + self.label = None + + # stores imol of currently loaded molecules and maps + self.mol_dict = { + "protein": -1, + "ligand": -1, + "2fofc": -1, + "fofc": -1, + "event": -1, + } + + # two dictionaries which are flushed when a new crystal is loaded + # and which contain information to update the data source if necessary + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + + self.label_button_list = [] + + ################################################################################ + # some COOT settings + coot.set_map_radius(17) + coot.set_colour_map_rotation_for_map(0) + + self.QualityIndicators = { + "RefinementRcryst": "-", + "RefinementRfree": "-", + "RefinementRfreeTraficLight": "gray", + "RefinementResolution": "-", + "RefinementResolutionTL": "gray", + "RefinementMolProbityScore": "-", + "RefinementMolProbityScoreTL": "gray", + "RefinementRamachandranOutliers": "-", + "RefinementRamachandranOutliersTL": "gray", + "RefinementRamachandranFavored": "-", + "RefinementRamachandranFavoredTL": "gray", + "RefinementRmsdBonds": "-", + "RefinementRmsdBondsTL": "gray", + "RefinementRmsdAngles": "-", + "RefinementRmsdAnglesTL": "gray", + "RefinementMatrixWeight": "-", + } + + self.spider_plot_data = { + "PANDDA_site_ligand_id": "-", + "PANDDA_site_occupancy": "-", + "PANDDA_site_B_average": "-", + "PANDDA_site_B_ratio_residue_surroundings": "-", + "PANDDA_site_RSCC": "-", + "PANDDA_site_rmsd": "-", + "PANDDA_site_RSR": "-", + "PANDDA_site_RSZD": "-", + } + + # default refmac parameters + self.RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + } + + # XCE menu + menu = coot_gui.coot_menubar_menu("XCE") + + coot_gui.add_simple_coot_menu_menuitem( + menu, "set all occupanicies to 1", lambda func: self.reset_occupancy() + ) + + def StartGUI(self): + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_default_size(400, 800) + self.window.set_title("XChemExplorer") + self.vbox = gtk.VBox() # this is the main container + + ################################################################################ + # --- Sample Selection --- + + frame = gtk.Frame(label="Select Samples") + self.hbox_select_samples = gtk.HBox() + + self.cb_select_samples = gtk.combo_box_new_text() + self.cb_select_samples.connect("changed", self.set_selection_mode) + for citeria in self.selection_criteria: + self.cb_select_samples.append_text(citeria) + self.hbox_select_samples.add(self.cb_select_samples) + + self.select_samples_button = gtk.Button(label="GO") + self.select_samples_button.connect("clicked", self.get_samples_to_look_at) + self.hbox_select_samples.add(self.select_samples_button) + frame.add(self.hbox_select_samples) + self.vbox.pack_start(frame) + + ################################################################################ + # --- status window --- + frame = gtk.Frame() + self.status_label = gtk.Label() + frame.add(self.status_label) + self.vbox.pack_start(frame) + + ################################################################################ + # --- refinement protocol --- + frame = gtk.Frame() + self.refinementProtocolcheckbox = gtk.CheckButton("PanDDA model refinement)") + # callback is defined later + self.refinementProtocolcheckbox.set_active(True) + frame.add(self.refinementProtocolcheckbox) + self.vbox.pack_start(frame) + + ################################################################################ + # --- Refinement Statistics --- + # next comes a section which displays some global quality indicators + # a combination of labels and textview widgets, arranged in a table + + RRfreeLabel_frame = gtk.Frame() + self.RRfreeLabel = gtk.Label("R/Rfree") + RRfreeLabel_frame.add(self.RRfreeLabel) + self.RRfreeValue = gtk.Label( + self.QualityIndicators["RefinementRcryst"] + + "/" + + self.QualityIndicators["RefinementRfree"] + ) + RRfreeBox_frame = gtk.Frame() + self.RRfreeBox = gtk.EventBox() + self.RRfreeBox.add(self.RRfreeValue) + RRfreeBox_frame.add(self.RRfreeBox) + + ResolutionLabel_frame = gtk.Frame() + self.ResolutionLabel = gtk.Label("Resolution") + ResolutionLabel_frame.add(self.ResolutionLabel) + self.ResolutionValue = gtk.Label(self.QualityIndicators["RefinementResolution"]) + ResolutionBox_frame = gtk.Frame() + self.ResolutionBox = gtk.EventBox() + self.ResolutionBox.add(self.ResolutionValue) + ResolutionBox_frame.add(self.ResolutionBox) + + MolprobityScoreLabel_frame = gtk.Frame() + self.MolprobityScoreLabel = gtk.Label("MolprobityScore") + MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) + self.MolprobityScoreValue = gtk.Label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + MolprobityScoreBox_frame = gtk.Frame() + self.MolprobityScoreBox = gtk.EventBox() + self.MolprobityScoreBox.add(self.MolprobityScoreValue) + MolprobityScoreBox_frame.add(self.MolprobityScoreBox) + + RamachandranOutliersLabel_frame = gtk.Frame() + self.RamachandranOutliersLabel = gtk.Label("Rama Outliers") + RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) + self.RamachandranOutliersValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + RamachandranOutliersBox_frame = gtk.Frame() + self.RamachandranOutliersBox = gtk.EventBox() + self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) + RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) + + RamachandranFavoredLabel_frame = gtk.Frame() + self.RamachandranFavoredLabel = gtk.Label("Rama Favored") + RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) + self.RamachandranFavoredValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + RamachandranFavoredBox_frame = gtk.Frame() + self.RamachandranFavoredBox = gtk.EventBox() + self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) + RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) + + rmsdBondsLabel_frame = gtk.Frame() + self.rmsdBondsLabel = gtk.Label("rmsd(Bonds)") + rmsdBondsLabel_frame.add(self.rmsdBondsLabel) + self.rmsdBondsValue = gtk.Label(self.QualityIndicators["RefinementRmsdBonds"]) + rmsdBondsBox_frame = gtk.Frame() + self.rmsdBondsBox = gtk.EventBox() + self.rmsdBondsBox.add(self.rmsdBondsValue) + rmsdBondsBox_frame.add(self.rmsdBondsBox) + + rmsdAnglesLabel_frame = gtk.Frame() + self.rmsdAnglesLabel = gtk.Label("rmsd(Angles)") + rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) + self.rmsdAnglesValue = gtk.Label(self.QualityIndicators["RefinementRmsdAngles"]) + rmsdAnglesBox_frame = gtk.Frame() + self.rmsdAnglesBox = gtk.EventBox() + self.rmsdAnglesBox.add(self.rmsdAnglesValue) + rmsdAnglesBox_frame.add(self.rmsdAnglesBox) + + MatrixWeightLabel_frame = gtk.Frame() + self.MatrixWeightLabel = gtk.Label("Matrix Weight") + MatrixWeightLabel_frame.add(self.MatrixWeightLabel) + self.MatrixWeightValue = gtk.Label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + MatrixWeightBox_frame = gtk.Frame() + self.MatrixWeightBox = gtk.EventBox() + self.MatrixWeightBox.add(self.MatrixWeightValue) + MatrixWeightBox_frame.add(self.MatrixWeightBox) + + ligandIDLabel_frame = gtk.Frame() + self.ligandIDLabel = gtk.Label("Ligand ID") + ligandIDLabel_frame.add(self.ligandIDLabel) + self.ligandIDValue = gtk.Label(self.spider_plot_data["PANDDA_site_ligand_id"]) + ligandIDBox_frame = gtk.Frame() + self.ligandIDBox = gtk.EventBox() + self.ligandIDBox.add(self.ligandIDValue) + ligandIDBox_frame.add(self.ligandIDBox) + + ligand_occupancyLabel_frame = gtk.Frame() + self.ligand_occupancyLabel = gtk.Label("occupancy") + ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) + self.ligand_occupancyValue = gtk.Label( + self.spider_plot_data["PANDDA_site_occupancy"] + ) + ligand_occupancyBox_frame = gtk.Frame() + self.ligand_occupancyBox = gtk.EventBox() + self.ligand_occupancyBox.add(self.ligand_occupancyValue) + ligand_occupancyBox_frame.add(self.ligand_occupancyBox) + + ligand_BaverageLabel_frame = gtk.Frame() + self.ligand_BaverageLabel = gtk.Label("B average") + ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) + self.ligand_BaverageValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_average"] + ) + ligand_BaverageBox_frame = gtk.Frame() + self.ligand_BaverageBox = gtk.EventBox() + self.ligand_BaverageBox.add(self.ligand_BaverageValue) + ligand_BaverageBox_frame.add(self.ligand_BaverageBox) + + ligand_BratioSurroundingsLabel_frame = gtk.Frame() + self.ligand_BratioSurroundingsLabel = gtk.Label("B ratio") + ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) + self.ligand_BratioSurroundingsValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_ratio_residue_surroundings"] + ) + ligand_BratioSurroundingsBox_frame = gtk.Frame() + self.ligand_BratioSurroundingsBox = gtk.EventBox() + self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) + ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) + + ligand_RSCCLabel_frame = gtk.Frame() + self.ligand_RSCCLabel = gtk.Label("RSCC") + ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) + self.ligand_RSCCValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSCC"]) + ligand_RSCCBox_frame = gtk.Frame() + self.ligand_RSCCBox = gtk.EventBox() + self.ligand_RSCCBox.add(self.ligand_RSCCValue) + ligand_RSCCBox_frame.add(self.ligand_RSCCBox) + + ligand_rmsdLabel_frame = gtk.Frame() + self.ligand_rmsdLabel = gtk.Label("rmsd") + ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) + self.ligand_rmsdValue = gtk.Label(self.spider_plot_data["PANDDA_site_rmsd"]) + ligand_rmsdBox_frame = gtk.Frame() + self.ligand_rmsdBox = gtk.EventBox() + self.ligand_rmsdBox.add(self.ligand_rmsdValue) + ligand_rmsdBox_frame.add(self.ligand_rmsdBox) + + ligand_RSRLabel_frame = gtk.Frame() + self.ligand_RSRLabel = gtk.Label("RSR") + ligand_RSRLabel_frame.add(self.ligand_RSRLabel) + self.ligand_RSRValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSR"]) + ligand_RSRBox_frame = gtk.Frame() + self.ligand_RSRBox = gtk.EventBox() + self.ligand_RSRBox.add(self.ligand_RSRValue) + ligand_RSRBox_frame.add(self.ligand_RSRBox) + + ligand_RSZDLabel_frame = gtk.Frame() + self.ligand_RSZDLabel = gtk.Label("RSZD") + ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) + self.ligand_RSZDValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSZD"]) + ligand_RSZDBox_frame = gtk.Frame() + self.ligand_RSZDBox = gtk.EventBox() + self.ligand_RSZDBox.add(self.ligand_RSZDValue) + ligand_RSZDBox_frame.add(self.ligand_RSZDBox) + + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame() + self.table_left = gtk.Table(8, 2, False) + self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) + self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) + self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) + self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) + self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) + self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) + self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) + self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) + self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) + self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) + self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) + self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) + self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) + self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) + self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) + self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) + frame.add(self.table_left) + hbox.add(frame) + + frame = gtk.Frame() + self.table_right = gtk.Table(8, 2, False) + self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) + self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) + self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) + self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) + self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) + self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) + self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) + self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) + self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) + self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) + self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) + self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) + self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) + self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) + frame.add(self.table_right) + hbox.add(frame) + + outer_frame.add(hbox) + self.vbox.add(outer_frame) + + hbox = gtk.HBox() + button = gtk.Button(label="Show MolProbity to-do list") + button.connect("clicked", self.show_molprobity_to_do) + hbox.add(button) + # --- ground state mean map --- + self.ground_state_mean_map_button = gtk.Button( + label="Show ground state mean map" + ) + self.ground_state_mean_map_button.connect( + "clicked", self.show_ground_state_mean_map + ) + hbox.add(self.ground_state_mean_map_button) + self.vbox.add(hbox) + + self.vbox.pack_start(frame) + + ################################################################################ + # --- hbox for compound picture & spider_plot (formerly: refinement history) --- + frame = gtk.Frame() + self.hbox_for_info_graphics = gtk.HBox() + + # --- compound picture --- + compound_frame = gtk.Frame() + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image = gtk.Image() + self.image.set_from_pixbuf(self.pic) + compound_frame.add(self.image) + self.hbox_for_info_graphics.add(compound_frame) + + # --- Spider Plot --- + spider_plot_frame = gtk.Frame() + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image = gtk.Image() + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + spider_plot_frame.add(self.spider_plot_image) + self.hbox_for_info_graphics.add(spider_plot_frame) + + frame.add(self.hbox_for_info_graphics) + self.vbox.add(frame) + + ################################################################################ + outer_frame = gtk.Frame(label="Sample Navigator") + hboxSample = gtk.HBox() + + # --- crystal navigator combobox --- + frame = gtk.Frame() + self.vbox_sample_navigator = gtk.VBox() + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseXtal) + self.vbox_sample_navigator.add(self.cb) + # --- crystal navigator backward/forward button --- + self.PREVbutton = gtk.Button(label="<<<") + self.NEXTbutton = gtk.Button(label=">>>") + self.PREVbutton.connect("clicked", self.ChangeXtal, -1) + self.NEXTbutton.connect("clicked", self.ChangeXtal, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbutton) + hbox.pack_start(self.NEXTbutton) + self.vbox_sample_navigator.add(hbox) + frame.add(self.vbox_sample_navigator) + hboxSample.add(frame) + + # --- site navigator combobox --- + frame = gtk.Frame() + self.vbox_site_navigator = gtk.VBox() + self.cb_site = gtk.combo_box_new_text() + self.cb_site.connect("changed", self.ChooseSite) + self.vbox_site_navigator.add(self.cb_site) + # --- site navigator backward/forward button --- + self.PREVbuttonSite = gtk.Button(label="<<<") + self.NEXTbuttonSite = gtk.Button(label=">>>") + self.PREVbuttonSite.connect("clicked", self.ChangeSite, -1) + self.NEXTbuttonSite.connect("clicked", self.ChangeSite, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbuttonSite) + hbox.pack_start(self.NEXTbuttonSite) + self.vbox_site_navigator.add(hbox) + frame.add(self.vbox_site_navigator) + hboxSample.add(frame) + + outer_frame.add(hboxSample) + self.vbox.add(outer_frame) + + ################################################################################ + # --- current refinement stage --- + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame(label="Analysis Status") + vbox = gtk.VBox() + self.experiment_stage_button_list = [] + for n, button in enumerate(self.experiment_stage): + if n == 0: + new_button = gtk.RadioButton(None, button[0]) + else: + new_button = gtk.RadioButton(new_button, button[0]) + new_button.connect( + "toggled", self.experiment_stage_button_clicked, button[1] + ) + vbox.pack_start(new_button, False, False, 0) + self.experiment_stage_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + # --- ligand confidence --- + frame = gtk.Frame(label="Ligand Confidence") + vbox = gtk.VBox() + self.ligand_confidence_button_list = [] + for n, criteria in enumerate(self.ligand_confidence_category): + if n == 0: + new_button = gtk.RadioButton(None, criteria) + else: + new_button = gtk.RadioButton(new_button, criteria) + new_button.connect( + "toggled", self.ligand_confidence_button_clicked, criteria + ) + vbox.pack_start(new_button, False, False, 0) + self.ligand_confidence_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + outer_frame.add(hbox) + self.vbox.pack_start(outer_frame) + + # --- ligand modeling --- + frame = gtk.Frame(label="Ligand Modeling") + self.hbox_for_modeling = gtk.HBox() + self.merge_ligand_button = gtk.Button(label="Merge Ligand") + self.place_ligand_here_button = gtk.Button(label="Place Ligand here") + self.hbox_for_modeling.add(self.place_ligand_here_button) + self.place_ligand_here_button.connect("clicked", self.place_ligand_here) + self.hbox_for_modeling.add(self.merge_ligand_button) + self.merge_ligand_button.connect("clicked", self.merge_ligand_into_protein) + frame.add(self.hbox_for_modeling) + self.vbox.pack_start(frame) + + # --- refinement & options --- + self.hbox_for_refinement = gtk.HBox() + self.REFINEbutton = gtk.Button(label="Refine") + self.RefinementParamsButton = gtk.Button(label="refinement parameters") + self.REFINEbutton.connect("clicked", self.REFINE) + self.hbox_for_refinement.add(self.REFINEbutton) + self.RefinementParamsButton.connect("clicked", self.RefinementParams) + self.hbox_for_refinement.add(self.RefinementParamsButton) + self.vbox.add(self.hbox_for_refinement) + + # need to put it here, because attributes within refinementProtocolCallback + # function are defined after checkbox is defined + self.refinementProtocolcheckbox.connect( + "toggled", self.refinementProtocolCallback + ) + + # --- CANCEL button --- + self.CANCELbutton = gtk.Button(label="CANCEL") + self.CANCELbutton.connect("clicked", self.CANCEL) + self.vbox.add(self.CANCELbutton) + + self.window.add(self.vbox) + self.window.show_all() + + def CANCEL(self, widget): + self.window.destroy() + + def ChangeXtal(self, widget, data=None): + self.index = self.index + data + if self.index < 0: + self.index = 0 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def ChooseXtal(self, widget): + self.xtalID = str(widget.get_active_text()) + for n, item in enumerate(self.Todo): + if str(item[0]) == self.xtalID: + self.index = n + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + + self.refresh_site_combobox() + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + if str(self.Todo[self.index][0]) is not None: + self.compoundID = str(self.Todo[self.index][1]) + self.refinement_outcome = str(self.Todo[self.index][5]) + self.label = self.db.get_label_of_sample(self.xtalID) + self.update_RefinementOutcome_radiobutton() + if ( + self.xtalID not in self.siteDict + ): # i.e. we are not working with a PanDDA model + self.ligand_confidence = str(self.Todo[self.index][6]) + self.update_LigandConfidence_radiobutton() + self.label = self.db.get_label_of_sample(self.xtalID) + + self.RefreshData() + + def update_RefinementOutcome_radiobutton(self): + # updating dataset outcome radiobuttons + current_stage = 0 + for i, entry in enumerate(self.experiment_stage): + if entry[1].split()[0] == self.refinement_outcome.split()[0]: + current_stage = i + break + for i, button in enumerate(self.experiment_stage_button_list): + if i == current_stage: + button.set_active(True) + break + + def update_LigandConfidence_radiobutton(self): + # updating ligand confidence radiobuttons + current_stage = 0 + for i, entry in enumerate(self.ligand_confidence_category): + print("--->", entry, self.ligand_confidence) + try: + if entry.split()[0] == self.ligand_confidence.split()[0]: + current_stage = i + break + except IndexError: + pass + for i, button in enumerate(self.ligand_confidence_button_list): + if i == current_stage: + button.set_active(True) + break + + def refresh_site_combobox(self): + # reset self.pandda_index + self.pandda_index = -1 + # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever + # be 100 sites + for n in range(-1, 100): + self.cb_site.remove_text(0) + self.site_index = "0" + self.event_index = "0" + # only repopulate if site exists + if self.xtalID in self.siteDict: + for item in sorted(self.siteDict[self.xtalID]): + self.cb_site.append_text( + "site: {0!s} - event: {1!s}".format(item[5], item[6]) + ) + + def ChangeSite(self, widget, data=None): + if self.xtalID in self.siteDict: + self.pandda_index = self.pandda_index + data + if self.pandda_index < 0: + self.pandda_index = 0 + if self.pandda_index >= len(self.siteDict[self.xtalID]): + self.pandda_index = 0 + self.cb_site.set_active(self.pandda_index) + + def ChooseSite(self, widget): + tmp = str(widget.get_active_text()) + print(self.siteDict) + print(self.site_index) + self.site_index = tmp.split()[1] + self.event_index = tmp.split()[4] + for n, item in enumerate(self.siteDict[self.xtalID]): + if item[5] == self.site_index and item[6] == self.event_index: + self.pandda_index = n + self.RefreshSiteData() + + def RefreshSiteData(self): + if self.pandda_index == -1: + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + else: + self.merge_ligand_button.set_sensitive(False) + self.place_ligand_here_button.set_sensitive(False) + # and remove ligand molecule so that there is no temptation to merge it + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if self.compoundID + ".pdb" in coot.molecule_name(imol): + coot.close_molecule(imol) + + for w in self.label_button_list: + w.set_active(False) + + print("pandda index", self.pandda_index) + self.spider_plot = self.siteDict[self.xtalID][self.pandda_index][4] + print("new spider plot:", self.spider_plot) + self.event_map = self.siteDict[self.xtalID][self.pandda_index][0] + print("new event map:", self.event_map) + self.ligand_confidence = str(self.siteDict[self.xtalID][self.pandda_index][7]) + self.update_LigandConfidence_radiobutton() + site_x = float(self.siteDict[self.xtalID][self.pandda_index][1]) + site_y = float(self.siteDict[self.xtalID][self.pandda_index][2]) + site_z = float(self.siteDict[self.xtalID][self.pandda_index][3]) + print("new site coordinates:", site_x, site_y, site_z) + coot.set_rotation_centre(site_x, site_y, site_z) + + self.spider_plot_data = ( + self.db.get_db_pandda_dict_for_sample_and_site_and_event( + self.xtalID, self.site_index, self.event_index + ) + ) + print(">>>>> spider plot data", self.spider_plot_data) + self.ligandIDValue.set_label(self.spider_plot_data["PANDDA_site_ligand_id"]) + try: + self.ligand_occupancyValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_occupancy"]), 2)) + ) + except ValueError: + self.ligand_occupancyValue.set_label("-") + + try: + self.ligand_BaverageValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_B_average"]), 2)) + ) + except ValueError: + self.ligand_BaverageValue.set_label("-") + + try: + self.ligand_BratioSurroundingsValue.set_label( + str( + round( + float( + self.spider_plot_data[ + "PANDDA_site_B_ratio_residue_surroundings" + ] + ), + 2, + ) + ) + ) + except ValueError: + self.ligand_BratioSurroundingsValue.set_label("-") + + try: + self.ligand_RSCCValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSCC"]), 2)) + ) + except ValueError: + self.ligand_RSCCValue.set_label("-") + + try: + self.ligand_rmsdValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_rmsd"]), 2)) + ) + except ValueError: + self.ligand_rmsdValue.set_label("-") + + try: + self.ligand_RSRValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSR"]), 2)) + ) + except ValueError: + self.ligand_RSRValue.set_label("-") + + try: + self.ligand_RSZDValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSZD"]), 2)) + ) + except ValueError: + self.ligand_RSZDValue.set_label("-") + + ################################################################################ + # delete old Event MAPs + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if "map.native.ccp4" in coot.molecule_name(imol): + coot.close_molecule(imol) + + ################################################################################ + # Spider plot + # Note: refinement history was shown instead previously + if os.path.isfile(self.spider_plot): + spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) + else: + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + ################################################################################ + # check for PANDDAs EVENT maps + if os.path.isfile(self.event_map): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.handle_read_ccp4_map((self.event_map), 0) + for imol in coot_utils_XChem.molecule_number_list(): + if self.event_map in coot.molecule_name(imol): + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + + def experiment_stage_button_clicked(self, widget, data=None): + if data == "4 - CompChem ready" and self.refinementProtocol.startswith( + "pandda" + ): + print( + "==> XCE: removing refine.pdb and linking" + " refine_.split.bound-state.pdb to refine.pdb" + ) + os.chdir(os.path.join(self.project_directory, self.xtalID)) + if os.path.realpath("refine.pdb").replace(".pdb", ".split.bound-state.pdb"): + newPDB = os.path.realpath("refine.pdb").replace( + ".pdb", ".split.bound-state.pdb" + ) + os.system("/bin/rm refine.pdb") + os.system("ln -s .%s refine.pdb" % newPDB.replace(os.getcwd(), "")) + self.refinementProtocolcheckbox.set_active(False) + self.refinementProtocol = "refmac" + else: + print("==> XCE ERROR: cannot find refine.output.bound-state.pdb") + pass + self.db_dict_mainTable["RefinementOutcome"] = data + print( + "==> XCE: setting Refinement Outcome for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.create_or_remove_missing_records_in_depositTable( + self.xce_logfile, self.xtalID, "ligand_bound", self.db_dict_mainTable + ) + + def ligand_confidence_button_clicked(self, widget, data=None): + print("PANDDA_index", self.pandda_index) + if self.pandda_index == -1: + self.db_dict_mainTable["RefinementLigandConfidence"] = data + print( + "==> XCE: setting Ligand Confidence for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.update_data_source(self.xtalID, self.db_dict_mainTable) + self.Todo[self.index][6] = data + else: + self.db_dict_panddaTable["PANDDA_site_confidence"] = data + print( + "==> XCE: setting Ligand Confidence for " + + self.xtalID + + " (site=" + + str(self.site_index) + + ", event=" + + str(self.event_index) + + ") to " + + str(data) + + " in panddaTable of datasource" + ) + self.db.update_site_event_panddaTable( + self.xtalID, self.site_index, self.event_index, self.db_dict_panddaTable + ) + self.siteDict[self.xtalID][self.pandda_index][7] = data + + def RefreshData(self): + # reset spider plot image + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + # reset ground state mean map + self.ground_state_mean_map = "" + self.ground_state_mean_map_button.set_sensitive(False) + self.ground_state_mean_map_button.set_label("Show ground state mean map") + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + ): + self.ground_state_mean_map_button.set_sensitive(True) + self.ground_state_mean_map = os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + + # initialize Refinement library + self.Refine = XChemRefine.Refine( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ) + self.Serial = XChemRefine.GetSerial(self.project_directory, self.xtalID) + self.panddaSerial = (4 - len(str(self.Serial))) * "0" + str(self.Serial) + if self.Serial == 1: + # i.e. no refinement has been done; data is probably straight out of dimple + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, self.pdb_style), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "init.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + + # all this information is now updated in the datasource after each refinement + # cycle + self.QualityIndicators = self.db.get_db_dict_for_sample(self.xtalID) + + ################################################################################ + # history + # if the structure was previously refined, try to read the parameters + if self.Serial > 1: + self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) + print("==> REFMAC params:", self.RefmacParams) + + ################################################################################ + # update pdb & maps + + ################################################################################ + # delete old PDB and MAP files + # - get a list of all molecules which are currently opened in COOT + # - remove all molecules/ maps before loading a new set + if len(coot_utils_XChem.molecule_number_list()) > 0: + for item in coot_utils_XChem.molecule_number_list(): + coot.close_molecule(item) + + ################################################################################ + # read new PDB files + # read protein molecule after ligand so that this one is the active molecule + coot.set_nomenclature_errors_on_read("ignore") + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.compoundID + ".pdb") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ), + 0, + ) + self.mol_dict["ligand"] = imol + coot.read_cif_dictionary( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ) + if not os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + + if self.refinementProtocol.startswith("pandda"): + print( + "=> XCE: looking for ground-state model", + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.ground-state.pdb", + ), + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.ground-state.pdb", + ) + ): + print("=> XCE: found ground-state model") + os.chdir(os.path.join(self.project_directory, self.xtalID)) + coot.set_colour_map_rotation_on_read_pdb(0) + try: + color_wheel_rotation = 160 / float(imol + 2) + except UnboundLocalError: + color_wheel_rotation = 80 + coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.ground-state.pdb", + ), + 0, + ) + coot.set_colour_by_molecule(imol) + coot.set_mol_active(imol, 0) + else: + print("=> XCE - ERROR: cannot find ground-state model") + print( + "=> XCE: looking for bound-state model", + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb", + ), + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb", + ) + ): + print("=> XCE: found bound-state model") + os.chdir(os.path.join(self.project_directory, self.xtalID)) + coot.set_colour_map_rotation_on_read_pdb(0) + color_wheel_rotation = 21 / float(imol + 2) + coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb", + ), + 0, + ) + self.mol_dict["protein"] = imol + else: + print("=> XCE - ERROR: cannot find bound-state model") + print("=> XCE: moving to next crystal...") + self.go_to_next_xtal() + else: + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, self.pdb_style), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "init.pdb"), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), 0 + ) + else: + self.go_to_next_xtal() + self.mol_dict["protein"] = imol + + # read any one event map if present + for event_map in glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-event_*.native.ccp4", + ) + ): + coot.handle_read_ccp4_map((event_map), 0) + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + break + + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) or coot.molecule_name(item).endswith(self.pdb_style): + # master switch to show symmetry molecules + coot.set_show_symmetry_master(1) + coot.set_show_symmetry_molecule(item, 1) # show symm for model + + ################################################################################ + # read fofc maps + # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map + # read 2fofc map last so that one can change its contour level + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "2fofc.map") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.set_default_initial_contour_level_for_difference_map(3) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "fofc.map"), 1 + ) + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "2fofc.map"), 0 + ) + coot.set_last_map_colour(0, 0, 1) + else: + # try to open mtz file with same name as pdb file + coot.set_default_initial_contour_level_for_map(1) + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "init.mtz") + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ) + + ################################################################################ + # update Quality Indicator table + try: + self.RRfreeValue.set_label( + str(round(float(self.QualityIndicators["RefinementRcryst"]), 3)) + + " / " + + str(round(float(self.QualityIndicators["RefinementRfree"]), 3)) + ) + except ValueError: + self.RRfreeValue.set_label("-") + + try: + self.RRfreeBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRfreeTraficLight"] + ), + ) + except ValueError: + pass + self.ResolutionValue.set_label(self.QualityIndicators["RefinementResolution"]) + try: + self.ResolutionBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementResolutionTL"]), + ) + except ValueError: + pass + self.MolprobityScoreValue.set_label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + try: + self.MolprobityScoreBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementMolProbityScoreTL"] + ), + ) + except ValueError: + pass + self.RamachandranOutliersValue.set_label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + try: + self.RamachandranOutliersBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranOutliersTL"] + ), + ) + except ValueError: + pass + self.RamachandranFavoredValue.set_label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + try: + self.RamachandranFavoredBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranFavoredTL"] + ), + ) + except ValueError: + pass + self.rmsdBondsValue.set_label(self.QualityIndicators["RefinementRmsdBonds"]) + try: + self.rmsdBondsBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdBondsTL"]), + ) + except ValueError: + pass + self.rmsdAnglesValue.set_label(self.QualityIndicators["RefinementRmsdAngles"]) + try: + self.rmsdAnglesBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdAnglesTL"]), + ) + except ValueError: + pass + self.MatrixWeightValue.set_label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + + try: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".png" + ) + ) + except gobject.GError: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image.set_from_pixbuf(self.pic) + + def go_to_next_xtal(self): + self.index += 1 + if self.index >= len(self.Todo): + self.index = len(self.Todo) + self.cb.set_active(self.index) + + def REFINE(self, widget): + if self.refinementProtocol.startswith("pandda"): + ####################################################### + if not os.path.isdir( + os.path.join(self.project_directory, self.xtalID, "cootOut") + ): + os.mkdir(os.path.join(self.project_directory, self.xtalID, "cootOut")) + # create folder for new refinement cycle + try: + os.mkdir( + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + ) + ) + except OSError: + print("==> XCE: WARNING -> folder exists; will overwrite contents!") + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ + # folder. note: the user has to make sure that the ligand file was merged + # into main file + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) or coot.molecule_name(item).endswith(self.pdb_style): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + "refine.modified.pdb", + ), + ) + break + + XChemRefine.panddaRefine( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ).RunQuickRefine( + self.Serial, + self.RefmacParams, + self.external_software, + self.xce_logfile, + self.refinementProtocol, + get_token(fetch_password_gtk), + ) + else: + ####################################################### + # create folder for new refinement cycle and check if free.mtz exists + if not os.path.isdir(os.path.join(self.project_directory, self.xtalID)): + os.mkdir(os.path.join(self.project_directory, self.xtalID)) + if not os.path.isdir( + os.path.join( + self.project_directory, self.xtalID, "Refine_" + str(self.Serial) + ) + ): + os.mkdir( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + ) + ) + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ + # folder. note: the user has to make sure that the ligand file was merged + # into main file + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith(self.pdb_style): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + elif coot.molecule_name(item).endswith("refine.split.bound-state.pdb"): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + elif coot.molecule_name(item).endswith("init.pdb"): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + elif coot.molecule_name(item).endswith("dimple.pdb"): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + + self.Refine.RunRefmac( + self.Serial, + self.RefmacParams, + self.external_software, + self.xce_logfile, + None, + get_token(fetch_password_gtk), + ) + + self.index += 1 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def RefinementParams(self, widget): + print("\n==> XCE: changing refinement parameters") + self.RefmacParams = XChemRefine.RefineParams( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ).RefmacRefinementParams(self.RefmacParams) + + def set_selection_mode(self, widget): + self.selection_mode = widget.get_active_text() + + def get_samples_to_look_at(self, widget): + if self.selection_mode == "": + self.status_label.set_text("select model stage") + return + self.status_label.set_text("checking datasource for samples... ") + # first remove old samples if present + if len(self.Todo) != 0: + for n, item in enumerate(self.Todo): + self.cb.remove_text(0) + self.Todo = [] + self.siteDict = {} + self.Todo, self.siteDict = self.db.get_todoList_for_coot(self.selection_mode) + # refresh sample CB + for item in sorted(self.Todo): + self.cb.append_text("{0!s}".format(item[0])) + if self.siteDict == {}: + self.cb_site.set_sensitive(False) + self.PREVbuttonSite.set_sensitive(False) + self.NEXTbuttonSite.set_sensitive(False) + else: + self.cb_site.set_sensitive(True) + self.PREVbuttonSite.set_sensitive(True) + self.NEXTbuttonSite.set_sensitive(True) + print("===========>", self.cb_select_samples.get_active_text()) + if int(self.cb_select_samples.get_active_text().split()[0]) > 3: + print( + "==> XCE: sorry cannot change refinement protocol since you are at a" + " stage when we refine the ligand bound state only" + ) + self.refinementProtocol = "refmac" + self.refinementProtocolcheckbox.set_active(False) + + def update_plot(self, refinement_cycle, Rfree, Rcryst): + fig = Figure(figsize=(2, 2), dpi=50) + Plot = fig.add_subplot(111) + Plot.set_ylim([0, max(Rcryst + Rfree)]) + Plot.set_xlabel("Refinement Cycle", fontsize=12) + Plot.plot(refinement_cycle, Rfree, label="Rfree", linewidth=2) + Plot.plot(refinement_cycle, Rcryst, label="Rcryst", linewidth=2) + Plot.legend( + bbox_to_anchor=(0.0, 1.02, 1.0, 0.102), + loc=3, + ncol=2, + mode="expand", + borderaxespad=0.0, + fontsize=12, + ) + return fig + + def place_ligand_here(self, widget): + print("===> XCE: moving ligand to pointer") + print("LIGAND: ", self.mol_dict["ligand"]) + coot_utils_XChem.move_molecule_here(self.mol_dict["ligand"]) + + def merge_ligand_into_protein(self, widget): + print("===> XCE: merge ligand into protein structure") + coot.merge_molecules_py([self.mol_dict["ligand"]], self.mol_dict["protein"]) + print("===> XCE: deleting ligand molecule") + coot.close_molecule(self.mol_dict["ligand"]) + + def show_molprobity_to_do(self, widget): + print(self.panddaSerial) + AdjPanddaSerial = (4 - len(str(self.Serial))) * "0" + str( + int(self.panddaSerial) - 1 + ) + print( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.panddaSerial), + "molprobity_coot.py", + ) + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + elif os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(AdjPanddaSerial), + "molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(AdjPanddaSerial), + "molprobity_coot.py", + ) + ) + else: + print( + "==> XCE: cannot find " + + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + + def refinementProtocolCallback(self, widget): + if widget.get_active(): + if self.refinementProtocolcheckbox.get_active(): + self.refinementProtocol = "pandda_phenix" + else: + self.refinementProtocol = "pandda_refmac" + self.PREVbuttonSite.set_sensitive(True) + self.NEXTbuttonSite.set_sensitive(True) + else: + self.refinementProtocolcheckbox.set_active(False) + self.refinementProtocol = "refmac" + self.PREVbuttonSite.set_sensitive(False) + self.NEXTbuttonSite.set_sensitive(False) + print(self.refinementProtocol) + + def show_ground_state_mean_map(self, widget): + if widget.get_label().startswith("Show"): + loaded = False + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 1) + loaded = True + break + if not loaded: + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map(self.ground_state_mean_map, 0) + coot.set_last_map_colour(0.6, 0.6, 0) + widget.set_label("Undisplay ground state mean map") + else: + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 0) + widget.set_label("Show ground state mean map") + + def reset_occupancy(self): + self.Logfile.warning( + "==> COOT: trying to set occupancies of all residues to 1.0" + ) + if self.refinementProtocol.startswith("pandda"): + self.Logfile.warning( + "==> COOT: you cannot reset occupancies while working in PanDDA" + " refine mode" + ) + else: + for imol in coot_utils_XChem.molecule_number_list(): + if ( + coot.molecule_name(imol).endswith(self.pdb_style) + or coot.molecule_name(imol).endswith("refine.split.bound-state.pdb") + or coot.molecule_name(imol).endswith("ini.pdb") + or coot.molecule_name(imol).endswith("dimple.pdb") + ): + self.Logfile.warning( + "==> COOT: setting occupancies of all protein residues in %s" + " to 1.0" % coot.molecule_name(imol) + ) + chains = coot_utils_XChem.chain_ids(imol) + resiDict = {} + for chain in chains: + resiDict[chain] = coot_utils.residues_in_chain(imol, chain) + amino_acids = XChemUtils.pdbtools( + coot.molecule_name(imol) + ).amino_acids() + + resetDict = {} + for chain in resiDict: + residRange = [] + start = None + resid_prev = -1000 + n_res = 0 + for resid in resiDict[chain]: + if ( + coot.residue_name(imol, chain, resid[1], "") + in amino_acids + ): + n_res += 1 + counter = 0 + for n, resid in enumerate(resiDict[chain]): + if ( + coot.residue_name(imol, chain, resid[1], "") + in amino_acids + ): + counter += 1 + if chain not in resetDict: + resetDict[chain] = None + if resid[1] != resid_prev + 1: + if resid_prev != -1000: + assert start is not None + residRange.append([start, resid_prev]) + start = resid[1] + resid_prev = resid[1] + if counter == n_res: + residRange.append([start, resid[1]]) + if chain in resetDict: + resetDict[chain] = residRange + for chain in resetDict: + for resid_range in resetDict[chain]: + print( + "setting occupancy to 1: ->", + chain, + resid_range[0], + resid_range[1], + ) + coot.fill_occupancy_residue_range( + imol, chain, resid_range[0], resid_range[1] + ) + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import coot_utils_XChem + from xce.lib import XChemDB + from xce.lib import XChemLog + from xce.lib import XChemRefine + from xce.lib import XChemUtils + from xce.lib.cluster.slurm import get_token, fetch_password_gtk + + GUI().StartGUI() diff --git a/coot/XChemCootBuster.py b/coot/XChemCootBuster.py new file mode 100755 index 00000000..e6a55d5c --- /dev/null +++ b/coot/XChemCootBuster.py @@ -0,0 +1,1693 @@ +import sys +import getpass +import glob +import os +import pickle +from datetime import datetime + +import coot +import gobject +import gtk +from matplotlib.figure import Figure + +# had to adapt the original coot_utils.py file +# otherwise unable to import the original file without complaints about missing modules +# etc. +# modified file is now in $XChemExplorer_DIR/lib + + +class GUI(object): + """ + main class which opens the actual GUI + """ + + def __init__(self): + ################################################################################ + # read in settings file from XChemExplorer to set the relevant paths + self.settings = pickle.load(open(".xce_settings.pkl", "rb")) + + self.database_directory = self.settings["database_directory"] + self.xce_logfile = self.settings["xce_logfile"] + self.Logfile = XChemLog.updateLog(self.xce_logfile) + self.Logfile.insert("==> COOT: starting coot plugin...") + self.data_source = self.settings["data_source"] + self.db = XChemDB.data_source(self.data_source) + + print(self.settings) + + # checking for external software packages + self.external_software = XChemUtils.external_software(self.xce_logfile).check() + + self.selection_criteria = [ + "0 - All Datasets", + "1 - Analysis Pending", + "2 - PANDDA model", + "3 - In Refinement", + "4 - CompChem ready", + "5 - Deposition ready", + "6 - Deposited", + "7 - Analysed & Rejected", + ] + + self.experiment_stage = [ + ["Review PANDDA export", "2 - PANDDA model", 65000, 0, 0], + ["In Refinement", "3 - In Refinement", 65000, 0, 0], + ["Comp Chem Ready!", "4 - CompChem ready", 65000, 0, 0], + ["Ready for Deposition!", "5 - Deposition ready", 65000, 0, 0], + ["In PDB", "6 - Deposited", 65000, 0, 0], + ["Analysed & Rejected", "7 - Analysed & Rejected", 65000, 0, 0], + ] + + self.ligand_confidence_category = [ + "0 - no ligand present", + "1 - Low Confidence", + "2 - Correct ligand, weak density", + "3 - Clear density, unexpected ligand", + "4 - High Confidence", + ] + + # this decides which samples will be looked at + self.selection_mode = "" + self.pandda_index = -1 # refers to the number of sites + self.site_index = "0" + self.event_index = "0" + + # the Folder is kind of a legacy thing because my inital idea was to have + # separate folders for Data Processing and Refinement + self.project_directory = self.settings["initial_model_directory"] + self.Serial = 0 + self.panddaSerial = 0 + self.Refine = None + self.index = -1 + self.Todo = [] + self.siteDict = {} + + self.xtalID = "" + self.compoundID = "" + self.ground_state_mean_map = "" + self.spider_plot = "" + self.ligand_confidence = "" + + self.pdb_style = "refine.pdb" + self.mtz_style = "refine.mtz" + + self.covLinkObject = coot.new_generic_object_number("covalent bond") + self.covLinkAtomSpec = None + + self.label = None + + # stores imol of currently loaded molecules and maps + self.mol_dict = { + "protein": -1, + "ligand": -1, + "2fofc": -1, + "fofc": -1, + "event": -1, + "ligand_stereo": [], + } + + # two dictionaries which are flushed when a new crystal is loaded + # and which contain information to update the data source if necessary + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + + self.label_button_list = [] + + ################################################################################ + # some COOT settings + coot.set_map_radius(17) + coot.set_colour_map_rotation_for_map(0) + # coot.set_colour_map_rotation_on_read_pdb_flag(21) + + self.QualityIndicators = { + "RefinementRcryst": "-", + "RefinementRfree": "-", + "RefinementRfreeTraficLight": "gray", + "RefinementResolution": "-", + "RefinementResolutionTL": "gray", + "RefinementMolProbityScore": "-", + "RefinementMolProbityScoreTL": "gray", + "RefinementRamachandranOutliers": "-", + "RefinementRamachandranOutliersTL": "gray", + "RefinementRamachandranFavored": "-", + "RefinementRamachandranFavoredTL": "gray", + "RefinementRmsdBonds": "-", + "RefinementRmsdBondsTL": "gray", + "RefinementRmsdAngles": "-", + "RefinementRmsdAnglesTL": "gray", + "RefinementMatrixWeight": "-", + } + + self.spider_plot_data = { + "PANDDA_site_ligand_id": "-", + "PANDDA_site_occupancy": "-", + "PANDDA_site_B_average": "-", + "PANDDA_site_B_ratio_residue_surroundings": "-", + "PANDDA_site_RSCC": "-", + "PANDDA_site_rmsd": "-", + "PANDDA_site_RSR": "-", + "PANDDA_site_RSZD": "-", + } + + # default refmac parameters + self.RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + "WATER": "", + "LIGOCC": "", + "SANITY": "", + } + + def StartGUI(self): + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_default_size(400, 800) + self.window.set_title("XChemExplorer") + self.vbox = gtk.VBox() # this is the main container + + ################################################################################ + # --- Sample Selection --- + + frame = gtk.Frame(label="Select Samples") + self.hbox_select_samples = gtk.HBox() + + self.cb_select_samples = gtk.combo_box_new_text() + self.cb_select_samples.connect("changed", self.set_selection_mode) + for citeria in self.selection_criteria: + self.cb_select_samples.append_text(citeria) + self.hbox_select_samples.add(self.cb_select_samples) + + self.select_samples_button = gtk.Button(label="GO") + self.select_samples_button.connect("clicked", self.get_samples_to_look_at) + self.hbox_select_samples.add(self.select_samples_button) + frame.add(self.hbox_select_samples) + self.vbox.pack_start(frame) + + ################################################################################ + # --- status window --- + frame = gtk.Frame() + self.status_label = gtk.Label() + frame.add(self.status_label) + self.vbox.pack_start(frame) + + ################################################################################ + # --- Refinement Statistics --- + # next comes a section which displays some global quality indicators + # a combination of labels and textview widgets, arranged in a table + + RRfreeLabel_frame = gtk.Frame() + self.RRfreeLabel = gtk.Label("R/Rfree") + RRfreeLabel_frame.add(self.RRfreeLabel) + self.RRfreeValue = gtk.Label( + self.QualityIndicators["RefinementRcryst"] + + "/" + + self.QualityIndicators["RefinementRfree"] + ) + RRfreeBox_frame = gtk.Frame() + self.RRfreeBox = gtk.EventBox() + self.RRfreeBox.add(self.RRfreeValue) + RRfreeBox_frame.add(self.RRfreeBox) + + ResolutionLabel_frame = gtk.Frame() + self.ResolutionLabel = gtk.Label("Resolution") + ResolutionLabel_frame.add(self.ResolutionLabel) + self.ResolutionValue = gtk.Label(self.QualityIndicators["RefinementResolution"]) + ResolutionBox_frame = gtk.Frame() + self.ResolutionBox = gtk.EventBox() + self.ResolutionBox.add(self.ResolutionValue) + ResolutionBox_frame.add(self.ResolutionBox) + + MolprobityScoreLabel_frame = gtk.Frame() + self.MolprobityScoreLabel = gtk.Label("MolprobityScore") + MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) + self.MolprobityScoreValue = gtk.Label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + MolprobityScoreBox_frame = gtk.Frame() + self.MolprobityScoreBox = gtk.EventBox() + self.MolprobityScoreBox.add(self.MolprobityScoreValue) + MolprobityScoreBox_frame.add(self.MolprobityScoreBox) + + RamachandranOutliersLabel_frame = gtk.Frame() + self.RamachandranOutliersLabel = gtk.Label("Rama Outliers") + RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) + self.RamachandranOutliersValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + RamachandranOutliersBox_frame = gtk.Frame() + self.RamachandranOutliersBox = gtk.EventBox() + self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) + RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) + + RamachandranFavoredLabel_frame = gtk.Frame() + self.RamachandranFavoredLabel = gtk.Label("Rama Favored") + RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) + self.RamachandranFavoredValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + RamachandranFavoredBox_frame = gtk.Frame() + self.RamachandranFavoredBox = gtk.EventBox() + self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) + RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) + + rmsdBondsLabel_frame = gtk.Frame() + self.rmsdBondsLabel = gtk.Label("rmsd(Bonds)") + rmsdBondsLabel_frame.add(self.rmsdBondsLabel) + self.rmsdBondsValue = gtk.Label(self.QualityIndicators["RefinementRmsdBonds"]) + rmsdBondsBox_frame = gtk.Frame() + self.rmsdBondsBox = gtk.EventBox() + self.rmsdBondsBox.add(self.rmsdBondsValue) + rmsdBondsBox_frame.add(self.rmsdBondsBox) + + rmsdAnglesLabel_frame = gtk.Frame() + self.rmsdAnglesLabel = gtk.Label("rmsd(Angles)") + rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) + self.rmsdAnglesValue = gtk.Label(self.QualityIndicators["RefinementRmsdAngles"]) + rmsdAnglesBox_frame = gtk.Frame() + self.rmsdAnglesBox = gtk.EventBox() + self.rmsdAnglesBox.add(self.rmsdAnglesValue) + rmsdAnglesBox_frame.add(self.rmsdAnglesBox) + + MatrixWeightLabel_frame = gtk.Frame() + self.MatrixWeightLabel = gtk.Label("Matrix Weight") + MatrixWeightLabel_frame.add(self.MatrixWeightLabel) + self.MatrixWeightValue = gtk.Label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + MatrixWeightBox_frame = gtk.Frame() + self.MatrixWeightBox = gtk.EventBox() + self.MatrixWeightBox.add(self.MatrixWeightValue) + MatrixWeightBox_frame.add(self.MatrixWeightBox) + + ligandIDLabel_frame = gtk.Frame() + self.ligandIDLabel = gtk.Label("Ligand ID") + ligandIDLabel_frame.add(self.ligandIDLabel) + self.ligandIDValue = gtk.Label(self.spider_plot_data["PANDDA_site_ligand_id"]) + ligandIDBox_frame = gtk.Frame() + self.ligandIDBox = gtk.EventBox() + self.ligandIDBox.add(self.ligandIDValue) + ligandIDBox_frame.add(self.ligandIDBox) + + ligand_occupancyLabel_frame = gtk.Frame() + self.ligand_occupancyLabel = gtk.Label("occupancy") + ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) + self.ligand_occupancyValue = gtk.Label( + self.spider_plot_data["PANDDA_site_occupancy"] + ) + ligand_occupancyBox_frame = gtk.Frame() + self.ligand_occupancyBox = gtk.EventBox() + self.ligand_occupancyBox.add(self.ligand_occupancyValue) + ligand_occupancyBox_frame.add(self.ligand_occupancyBox) + + ligand_BaverageLabel_frame = gtk.Frame() + self.ligand_BaverageLabel = gtk.Label("B average") + ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) + self.ligand_BaverageValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_average"] + ) + ligand_BaverageBox_frame = gtk.Frame() + self.ligand_BaverageBox = gtk.EventBox() + self.ligand_BaverageBox.add(self.ligand_BaverageValue) + ligand_BaverageBox_frame.add(self.ligand_BaverageBox) + + ligand_BratioSurroundingsLabel_frame = gtk.Frame() + self.ligand_BratioSurroundingsLabel = gtk.Label("B ratio") + ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) + self.ligand_BratioSurroundingsValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_ratio_residue_surroundings"] + ) + ligand_BratioSurroundingsBox_frame = gtk.Frame() + self.ligand_BratioSurroundingsBox = gtk.EventBox() + self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) + ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) + + ligand_RSCCLabel_frame = gtk.Frame() + self.ligand_RSCCLabel = gtk.Label("RSCC") + ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) + self.ligand_RSCCValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSCC"]) + ligand_RSCCBox_frame = gtk.Frame() + self.ligand_RSCCBox = gtk.EventBox() + self.ligand_RSCCBox.add(self.ligand_RSCCValue) + ligand_RSCCBox_frame.add(self.ligand_RSCCBox) + + ligand_rmsdLabel_frame = gtk.Frame() + self.ligand_rmsdLabel = gtk.Label("rmsd") + ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) + self.ligand_rmsdValue = gtk.Label(self.spider_plot_data["PANDDA_site_rmsd"]) + ligand_rmsdBox_frame = gtk.Frame() + self.ligand_rmsdBox = gtk.EventBox() + self.ligand_rmsdBox.add(self.ligand_rmsdValue) + ligand_rmsdBox_frame.add(self.ligand_rmsdBox) + + ligand_RSRLabel_frame = gtk.Frame() + self.ligand_RSRLabel = gtk.Label("RSR") + ligand_RSRLabel_frame.add(self.ligand_RSRLabel) + self.ligand_RSRValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSR"]) + ligand_RSRBox_frame = gtk.Frame() + self.ligand_RSRBox = gtk.EventBox() + self.ligand_RSRBox.add(self.ligand_RSRValue) + ligand_RSRBox_frame.add(self.ligand_RSRBox) + + ligand_RSZDLabel_frame = gtk.Frame() + self.ligand_RSZDLabel = gtk.Label("RSZD") + ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) + self.ligand_RSZDValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSZD"]) + ligand_RSZDBox_frame = gtk.Frame() + self.ligand_RSZDBox = gtk.EventBox() + self.ligand_RSZDBox.add(self.ligand_RSZDValue) + ligand_RSZDBox_frame.add(self.ligand_RSZDBox) + + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame() + self.table_left = gtk.Table(8, 2, False) + self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) + self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) + self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) + self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) + self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) + self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) + self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) + self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) + self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) + self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) + self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) + self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) + self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) + self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) + self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) + self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) + frame.add(self.table_left) + hbox.add(frame) + + frame = gtk.Frame() + self.table_right = gtk.Table(8, 2, False) + self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) + self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) + self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) + self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) + self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) + self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) + self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) + self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) + self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) + self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) + self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) + self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) + self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) + self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) + frame.add(self.table_right) + hbox.add(frame) + + outer_frame.add(hbox) + self.vbox.add(outer_frame) + + hbox = gtk.HBox() + button = gtk.Button(label="Show MolProbity to-do list") + button.connect("clicked", self.show_molprobity_to_do) + hbox.add(button) + # --- ground state mean map --- + self.ground_state_mean_map_button = gtk.Button( + label="Show ground state mean map" + ) + self.ground_state_mean_map_button.connect( + "clicked", self.show_ground_state_mean_map + ) + hbox.add(self.ground_state_mean_map_button) + self.vbox.add(hbox) + + self.vbox.pack_start(frame) + + ################################################################################ + # --- hbox for compound picture & spider_plot (formerly: refinement history) --- + frame = gtk.Frame() + self.hbox_for_info_graphics = gtk.HBox() + + # --- compound picture --- + compound_frame = gtk.Frame() + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image = gtk.Image() + self.image.set_from_pixbuf(self.pic) + compound_frame.add(self.image) + self.hbox_for_info_graphics.add(compound_frame) + + # --- Spider Plot --- + spider_plot_frame = gtk.Frame() + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image = gtk.Image() + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + spider_plot_frame.add(self.spider_plot_image) + self.hbox_for_info_graphics.add(spider_plot_frame) + + frame.add(self.hbox_for_info_graphics) + self.vbox.add(frame) + + ################################################################################ + outer_frame = gtk.Frame(label="Sample Navigator") + hboxSample = gtk.HBox() + + # --- crystal navigator combobox --- + frame = gtk.Frame() + self.vbox_sample_navigator = gtk.VBox() + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseXtal) + self.vbox_sample_navigator.add(self.cb) + # --- crystal navigator backward/forward button --- + self.PREVbutton = gtk.Button(label="<<<") + self.NEXTbutton = gtk.Button(label=">>>") + self.PREVbutton.connect("clicked", self.ChangeXtal, -1) + self.NEXTbutton.connect("clicked", self.ChangeXtal, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbutton) + hbox.pack_start(self.NEXTbutton) + self.vbox_sample_navigator.add(hbox) + frame.add(self.vbox_sample_navigator) + hboxSample.add(frame) + + # --- site navigator combobox --- + frame = gtk.Frame() + self.vbox_site_navigator = gtk.VBox() + self.cb_site = gtk.combo_box_new_text() + self.cb_site.connect("changed", self.ChooseSite) + self.vbox_site_navigator.add(self.cb_site) + # --- site navigator backward/forward button --- + self.PREVbuttonSite = gtk.Button(label="<<<") + self.NEXTbuttonSite = gtk.Button(label=">>>") + self.PREVbuttonSite.connect("clicked", self.ChangeSite, -1) + self.NEXTbuttonSite.connect("clicked", self.ChangeSite, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbuttonSite) + hbox.pack_start(self.NEXTbuttonSite) + self.vbox_site_navigator.add(hbox) + frame.add(self.vbox_site_navigator) + hboxSample.add(frame) + + outer_frame.add(hboxSample) + self.vbox.add(outer_frame) + + ################################################################################ + # --- current refinement stage --- + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame(label="Analysis Status") + vbox = gtk.VBox() + self.experiment_stage_button_list = [] + for n, button in enumerate(self.experiment_stage): + if n == 0: + new_button = gtk.RadioButton(None, button[0]) + else: + new_button = gtk.RadioButton(new_button, button[0]) + new_button.connect( + "toggled", self.experiment_stage_button_clicked, button[1] + ) + vbox.pack_start(new_button, False, False, 0) + self.experiment_stage_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + # --- ligand confidence --- + frame = gtk.Frame(label="Ligand Confidence") + vbox = gtk.VBox() + self.ligand_confidence_button_list = [] + for n, criteria in enumerate(self.ligand_confidence_category): + if n == 0: + new_button = gtk.RadioButton(None, criteria) + else: + new_button = gtk.RadioButton(new_button, criteria) + new_button.connect( + "toggled", self.ligand_confidence_button_clicked, criteria + ) + vbox.pack_start(new_button, False, False, 0) + self.ligand_confidence_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + outer_frame.add(hbox) + self.vbox.pack_start(outer_frame) + + # --- ligand modeling --- + frame = gtk.Frame(label="Ligand Modeling") + self.hbox_for_modeling = gtk.HBox() + self.merge_ligand_button = gtk.Button(label="Merge Ligand") + self.place_ligand_here_button = gtk.Button(label="Place Ligand here") + self.hbox_for_modeling.add(self.place_ligand_here_button) + self.place_ligand_here_button.connect("clicked", self.place_ligand_here) + self.hbox_for_modeling.add(self.merge_ligand_button) + self.merge_ligand_button.connect("clicked", self.merge_ligand_into_protein) + self.select_cpd_cb = gtk.combo_box_new_text() + self.select_cpd_cb.connect("changed", self.select_cpd) + self.hbox_for_modeling.add(self.select_cpd_cb) + frame.add(self.hbox_for_modeling) + self.vbox.pack_start(frame) + + # --- refinement & options --- + self.hbox_for_refinement = gtk.HBox() + self.REFINEbutton = gtk.Button(label="Refine") + self.RefinementParamsButton = gtk.Button(label="refinement parameters") + self.covalentLinksbutton = gtk.Button(label="covalent links\n-define-") + self.covalentLinksCreatebutton = gtk.Button( + label="covalent links\n-create & refine-" + ) + self.REFINEbutton.connect("clicked", self.REFINE) + self.hbox_for_refinement.add(self.REFINEbutton) + self.RefinementParamsButton.connect("clicked", self.RefinementParams) + self.covalentLinksbutton.connect("clicked", self.covalentLinkDef) + self.covalentLinksCreatebutton.connect("clicked", self.covalentLinkCreate) + self.hbox_for_refinement.add(self.RefinementParamsButton) + self.hbox_for_refinement.add(self.covalentLinksbutton) + self.hbox_for_refinement.add(self.covalentLinksCreatebutton) + self.vbox.add(self.hbox_for_refinement) + + # --- CANCEL button --- + self.CANCELbutton = gtk.Button(label="CANCEL") + self.CANCELbutton.connect("clicked", self.CANCEL) + self.vbox.add(self.CANCELbutton) + + self.window.add(self.vbox) + self.window.show_all() + + def CANCEL(self, widget): + self.window.destroy() + + def ChangeXtal(self, widget, data=None): + self.index = self.index + data + if self.index < 0: + self.index = 0 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def ChooseXtal(self, widget): + self.xtalID = str(widget.get_active_text()) + for n, item in enumerate(self.Todo): + if str(item[0]) == self.xtalID: + self.index = n + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + + self.refresh_site_combobox() + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + if str(self.Todo[self.index][0]) is not None: + self.compoundID = str(self.Todo[self.index][1]) + self.refinement_outcome = str(self.Todo[self.index][5]) + self.update_RefinementOutcome_radiobutton() + if ( + self.xtalID not in self.siteDict + ): # i.e. we are not working with a PanDDA model + self.ligand_confidence = str(self.Todo[self.index][6]) + + self.RefreshData() + + def select_cpd(self, widget): + cpd = str(widget.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if "rhofit" in coot.molecule_name(imol) or "phenix" in coot.molecule_name( + imol + ): + molNameCIF = ( + coot.molecule_name(imol)[coot.molecule_name(imol).rfind("/") + 1 :] + .replace(".pdb", "") + .replace("_phenix", "") + .replace("_rhofit", "") + ) + else: + molNameCIF = molName + print(cpd, "-", imol, "-", coot.molecule_name(imol)) + if molName == cpd: + coot.set_mol_displayed(imol, 1) + print( + "reading", + os.path.join( + self.project_directory, + self.xtalID, + "compound", + molNameCIF + ".cif", + ), + ) + coot.read_cif_dictionary( + os.path.join( + self.project_directory, + self.xtalID, + "compound", + molNameCIF + ".cif", + ) + ) + else: + coot.set_mol_displayed(imol, 0) + + def update_RefinementOutcome_radiobutton(self): + # updating dataset outcome radiobuttons + current_stage = 0 + for i, entry in enumerate(self.experiment_stage): + if entry[1].split()[0] == self.refinement_outcome.split()[0]: + current_stage = i + break + for i, button in enumerate(self.experiment_stage_button_list): + if i == current_stage: + button.set_active(True) + break + + def update_LigandConfidence_radiobutton(self): + # updating ligand confidence radiobuttons + current_stage = 0 + for i, entry in enumerate(self.ligand_confidence_category): + print("--->", entry, self.ligand_confidence) + try: + if entry.split()[0] == self.ligand_confidence.split()[0]: + current_stage = i + break + except IndexError: + pass + for i, button in enumerate(self.ligand_confidence_button_list): + if i == current_stage: + button.set_active(True) + break + + def refresh_site_combobox(self): + # reset self.pandda_index + self.pandda_index = -1 + # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever + # be 100 sites + for n in range(-1, 100): + self.cb_site.remove_text(0) + self.site_index = "0" + self.event_index = "0" + # only repopulate if site exists + if self.xtalID in self.siteDict: + for item in sorted(self.siteDict[self.xtalID]): + self.cb_site.append_text( + "site: {0!s} - event: {1!s}".format(item[5], item[6]) + ) + + def ChangeSite(self, widget, data=None): + if self.xtalID in self.siteDict: + self.pandda_index = self.pandda_index + data + if self.pandda_index < 0: + self.pandda_index = 0 + if self.pandda_index >= len(self.siteDict[self.xtalID]): + self.pandda_index = 0 + self.cb_site.set_active(self.pandda_index) + + def ChooseSite(self, widget): + tmp = str(widget.get_active_text()) + print(self.siteDict) + print(self.site_index) + self.site_index = tmp.split()[1] + self.event_index = tmp.split()[4] + for n, item in enumerate(self.siteDict[self.xtalID]): + if item[5] == self.site_index and item[6] == self.event_index: + self.pandda_index = n + self.RefreshSiteData() + + def RefreshSiteData(self): + if self.pandda_index == -1: + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + else: + self.merge_ligand_button.set_sensitive(False) + self.place_ligand_here_button.set_sensitive(False) + # and remove ligand molecule so that there is no temptation to merge it + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if self.compoundID + ".pdb" in coot.molecule_name(imol): + coot.close_molecule(imol) + + print("pandda index", self.pandda_index) + self.spider_plot = self.siteDict[self.xtalID][self.pandda_index][4] + print("new spider plot:", self.spider_plot) + self.event_map = self.siteDict[self.xtalID][self.pandda_index][0] + print("new event map:", self.event_map) + self.ligand_confidence = str(self.siteDict[self.xtalID][self.pandda_index][7]) + self.update_LigandConfidence_radiobutton() + site_x = float(self.siteDict[self.xtalID][self.pandda_index][1]) + site_y = float(self.siteDict[self.xtalID][self.pandda_index][2]) + site_z = float(self.siteDict[self.xtalID][self.pandda_index][3]) + print("new site coordinates:", site_x, site_y, site_z) + coot.set_rotation_centre(site_x, site_y, site_z) + + self.spider_plot_data = ( + self.db.get_db_pandda_dict_for_sample_and_site_and_event( + self.xtalID, self.site_index, self.event_index + ) + ) + print(">>>>> spider plot data", self.spider_plot_data) + self.ligandIDValue.set_label(self.spider_plot_data["PANDDA_site_ligand_id"]) + try: + self.ligand_occupancyValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_occupancy"]), 2)) + ) + except ValueError: + self.ligand_occupancyValue.set_label("-") + + try: + self.ligand_BaverageValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_B_average"]), 2)) + ) + except ValueError: + self.ligand_BaverageValue.set_label("-") + + try: + self.ligand_BratioSurroundingsValue.set_label( + str( + round( + float( + self.spider_plot_data[ + "PANDDA_site_B_ratio_residue_surroundings" + ] + ), + 2, + ) + ) + ) + except ValueError: + self.ligand_BratioSurroundingsValue.set_label("-") + + try: + self.ligand_RSCCValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSCC"]), 2)) + ) + except ValueError: + self.ligand_RSCCValue.set_label("-") + + try: + self.ligand_rmsdValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_rmsd"]), 2)) + ) + except ValueError: + self.ligand_rmsdValue.set_label("-") + + try: + self.ligand_RSRValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSR"]), 2)) + ) + except ValueError: + self.ligand_RSRValue.set_label("-") + + try: + self.ligand_RSZDValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSZD"]), 2)) + ) + except ValueError: + self.ligand_RSZDValue.set_label("-") + + ################################################################################ + # delete old Event MAPs + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if "map.native.ccp4" in coot.molecule_name(imol): + coot.close_molecule(imol) + + ################################################################################ + # Spider plot + # Note: refinement history was shown instead previously + if os.path.isfile(self.spider_plot): + spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) + else: + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + ################################################################################ + if os.path.isfile(self.event_map): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.handle_read_ccp4_map((self.event_map), 0) + for imol in coot_utils_XChem.molecule_number_list(): + if self.event_map in coot.molecule_name(imol): + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + + def experiment_stage_button_clicked(self, widget, data=None): + self.db_dict_mainTable["RefinementOutcome"] = data + self.db_dict_mainTable["RefinementOutcomePerson"] = getpass.getuser() + self.db_dict_mainTable["RefinementOutcomeDate"] = datetime.strftime( + datetime.now(), "%Y-%m-%d_%H-%M-%S.%f" + )[:-4] + + self.Logfile.insert( + "==> COOT: setting Refinement Outcome for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.create_or_remove_missing_records_in_depositTable( + self.xce_logfile, self.xtalID, "ligand_bound", self.db_dict_mainTable + ) + + def ligand_confidence_button_clicked(self, widget, data=None): + print("PANDDA_index", self.pandda_index) + if self.pandda_index == -1: + self.db_dict_mainTable["RefinementLigandConfidence"] = data + self.Logfile.insert( + "==> COOT: setting Ligand Confidence for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.update_data_source(self.xtalID, self.db_dict_mainTable) + self.Todo[self.index][6] = data + else: + self.db_dict_panddaTable["PANDDA_site_confidence"] = data + self.Logfile.insert( + "==> COOT: setting Ligand Confidence for " + + self.xtalID + + " (site=" + + str(self.site_index) + + ", event=" + + str(self.event_index) + + ") to " + + str(data) + + " in panddaTable of datasource" + ) + self.db.update_site_event_panddaTable( + self.xtalID, self.site_index, self.event_index, self.db_dict_panddaTable + ) + self.siteDict[self.xtalID][self.pandda_index][7] = data + + def RefreshData(self): + # reset spider plot image + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + # reset ground state mean map + self.ground_state_mean_map = "" + self.ground_state_mean_map_button.set_sensitive(False) + self.ground_state_mean_map_button.set_label("Show ground state mean map") + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + ): + self.ground_state_mean_map_button.set_sensitive(True) + self.ground_state_mean_map = os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + + # initialize Refinement library + self.Refine = XChemRefine.Refine( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ) + self.Serial = XChemRefine.GetSerial(self.project_directory, self.xtalID) + self.panddaSerial = (4 - len(str(self.Serial))) * "0" + str(self.Serial) + if self.Serial == 1: + # i.e. no refinement has been done; data is probably straight out of dimple + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, self.pdb_style), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "init.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + + # all this information is now updated in the datasource after each refinement + # cycle + self.QualityIndicators = self.db.get_db_dict_for_sample(self.xtalID) + + ################################################################################ + # history + # if the structure was previously refined, try to read the parameters + # self.hbox_for_info_graphics.remove(self.canvas) + if self.Serial > 1: + self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) + print("==> REFMAC params:", self.RefmacParams) + + ################################################################################ + # ligand files + # first remove old samples if present + print(">>>", self.mol_dict["ligand_stereo"]) + for n, item in enumerate(self.mol_dict["ligand_stereo"]): + print("__", item) + self.select_cpd_cb.remove_text(0) + print("done") + + ################################################################################ + # remove potential generic line which indicates a possible covalent link + coot.generic_object_clear(self.covLinkObject) + self.covLinkAtomSpec = None + + ################################################################################ + # update pdb & maps + + ################################################################################ + # delete old PDB and MAP files + # - get a list of all molecules which are currently opened in COOT + # - remove all molecules/ maps before loading a new set + if len(coot_utils_XChem.molecule_number_list()) > 0: + for item in coot_utils_XChem.molecule_number_list(): + coot.close_molecule(item) + + ################################################################################ + # read new PDB files + # read protein molecule after ligand so that this one is the active molecule + coot.set_nomenclature_errors_on_read("ignore") + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.compoundID + ".pdb") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ), + 0, + ) + self.mol_dict["ligand"] = imol + coot.read_cif_dictionary( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ) + self.select_cpd_cb.append_text(self.compoundID) + self.mol_dict["ligand_stereo"] = [] + self.mol_dict["ligand_stereo"].append(imol) + # ligands in compound directory + for cifFile in sorted( + glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + "compound", + self.compoundID + "_*.pdb", + ) + ) + ): + cif = cifFile[cifFile.rfind("/") + 1 :] + if "_with_H" in cif: + continue + self.select_cpd_cb.append_text(cif.replace(".pdb", "")) + imol = coot.handle_read_draw_molecule_with_recentre(cifFile, 0) + self.mol_dict["ligand_stereo"].append(imol) + coot.set_mol_displayed(imol, 0) + # autofitted ligands + for pdbFile in sorted( + glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + "autofit_ligand", + "*", + "*.pdb", + ) + ) + ): + autofitRun = pdbFile.split("/")[len(pdbFile.split("/")) - 2] + if pdbFile.endswith(autofitRun + ".pdb"): + self.select_cpd_cb.append_text(autofitRun) + imol = coot.handle_read_draw_molecule_with_recentre(pdbFile, 0) + self.mol_dict["ligand_stereo"].append(imol) + coot.set_mol_displayed(imol, 0) + self.select_cpd_cb.set_sensitive(True) + self.select_cpd_cb.set_active(0) + else: + print("no compound found in sample directory") + self.select_cpd_cb.set_sensitive(False) + + if not os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, self.pdb_style), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "init.pdb"), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), 0 + ) + else: + self.go_to_next_xtal() + self.mol_dict["protein"] = imol + + # read any one event map if present + for event_map in glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-event_*.native.ccp4", + ) + ): + coot.handle_read_ccp4_map((event_map), 0) + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + break + + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) or coot.molecule_name(item).endswith(self.pdb_style): + # master switch to show symmetry molecules + coot.set_show_symmetry_master(1) + coot.set_show_symmetry_molecule(item, 1) # show symm for model + + ################################################################################ + # read fofc maps + # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map + # read 2fofc map last so that one can change its contour level + # coot 0.9 does not handle P1 maps well, so now looking for non-existent map in + # order to trigger map calculation from mtz file + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "2fofc_??????.map") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.set_default_initial_contour_level_for_difference_map(3) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "fofc.map"), 1 + ) + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "2fofc.map"), 0 + ) + coot.set_last_map_colour(0, 0, 1) + else: + coot.set_colour_map_rotation_on_read_pdb(0) + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "init.mtz") + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ) + + ################################################################################ + # update Quality Indicator table + try: + self.RRfreeValue.set_label( + str(round(float(self.QualityIndicators["RefinementRcryst"]), 3)) + + " / " + + str(round(float(self.QualityIndicators["RefinementRfree"]), 3)) + ) + except ValueError: + self.RRfreeValue.set_label("-") + + try: + self.RRfreeBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRfreeTraficLight"] + ), + ) + except ValueError: + pass + self.ResolutionValue.set_label(self.QualityIndicators["RefinementResolution"]) + try: + self.ResolutionBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementResolutionTL"]), + ) + except ValueError: + pass + self.MolprobityScoreValue.set_label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + try: + self.MolprobityScoreBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementMolProbityScoreTL"] + ), + ) + except ValueError: + pass + self.RamachandranOutliersValue.set_label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + try: + self.RamachandranOutliersBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranOutliersTL"] + ), + ) + except ValueError: + pass + self.RamachandranFavoredValue.set_label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + try: + self.RamachandranFavoredBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranFavoredTL"] + ), + ) + except ValueError: + pass + self.rmsdBondsValue.set_label(self.QualityIndicators["RefinementRmsdBonds"]) + try: + self.rmsdBondsBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdBondsTL"]), + ) + except ValueError: + pass + self.rmsdAnglesValue.set_label(self.QualityIndicators["RefinementRmsdAngles"]) + try: + self.rmsdAnglesBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdAnglesTL"]), + ) + except ValueError: + pass + self.MatrixWeightValue.set_label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + + try: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".png" + ) + ) + except gobject.GError: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image.set_from_pixbuf(self.pic) + + def go_to_next_xtal(self): + self.index += 1 + if self.index >= len(self.Todo): + self.index = len(self.Todo) + self.cb.set_active(self.index) + + def REFINE(self, widget): + self.start_refinement() + + def start_refinement(self): + if not os.path.isdir( + os.path.join(self.project_directory, self.xtalID, "cootOut") + ): + os.mkdir(os.path.join(self.project_directory, self.xtalID, "cootOut")) + # create folder for new refinement cycle + try: + self.Logfile.insert( + "==> COOT: trying to make folder: %s" + % os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + ) + ) + os.mkdir( + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + ) + ) + except OSError: + self.Logfile.warning("==> COOT: folder exists; will overwrite contents!") + self.Logfile.warning( + "==> COOT: it is advised to check the sample directory" + " as this might be a symptom for a PDB file problem" + ) + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ folder + # note: the user has to make sure that the ligand file was merged into main file + foundPDB = False + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith(self.pdb_style): + foundPDB = True + break + elif coot.molecule_name(item).endswith("refine.split.bound-state.pdb"): + foundPDB = True + break + elif coot.molecule_name(item).endswith("init.pdb"): + foundPDB = True + break + elif coot.molecule_name(item).endswith("dimple.pdb"): + foundPDB = True + break + if foundPDB: + coot.delete_hydrogens(item) + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + + self.Refine.RunBuster( + self.Serial, + self.RefmacParams, + self.external_software, + self.xce_logfile, + self.covLinkAtomSpec, + get_token(fetch_password_gtk), + ) + self.index += 1 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def RefinementParams(self, widget): + print("\n==> XCE: changing refinement parameters") + self.RefmacParams = XChemRefine.RefineParams( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ).RefmacRefinementParams(self.RefmacParams) + print(self.RefmacParams) + + def covalentLinkDef(self, widget): + coot.user_defined_click_py(2, self.show_potential_link) + + def show_potential_link(self, *clicks): + # first find imol of protein molecule + # it's a prerequisite that the ligand is merged into the protein + imol_protein = None + for imol in coot_utils_XChem.molecule_number_list(): + print(">", coot.molecule_name(imol)) + if ( + coot.molecule_name(imol).endswith(self.pdb_style) + or coot.molecule_name(imol).endswith("init.pdb") + or coot.molecule_name(imol).endswith("dimple.pdb") + or coot.molecule_name(imol).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) + ): + imol_protein = imol + break + + print("please click on the two atoms you want to link") + if len(clicks) == 2: + click_1 = clicks[0] + click_2 = clicks[1] + imol_1 = click_1[1] + imol_2 = click_2[1] + print("imolp", imol, "imo11", imol_1, "imol2", imol_2) + if imol_1 == imol_2 and imol_1 == imol_protein: + print("click_1", click_1) + self.covLinkAtomSpec = None + xyz_1 = coot.atom_info_string_py( + click_1[1], + click_1[2], + click_1[3], + click_1[4], + click_1[5], + click_1[6], + ) + residue_1 = coot.residue_name( + click_1[1], click_1[2], click_1[3], click_1[4] + ) + xyz_2 = coot.atom_info_string_py( + click_2[1], + click_2[2], + click_2[3], + click_2[4], + click_2[5], + click_2[6], + ) + residue_2 = coot.residue_name( + click_2[1], click_2[2], click_2[3], click_2[4] + ) + thick = 4 + coot.to_generic_object_add_line( + self.covLinkObject, + "yellowtint", + thick, + xyz_1[3], + xyz_1[4], + xyz_1[5], + xyz_2[3], + xyz_2[4], + xyz_2[5], + ) + coot.set_display_generic_object(self.covLinkObject, 1) + self.covLinkAtomSpec = [ + imol_protein, + click_1, + click_2, + residue_1, + residue_2, + ] + else: + print( + "error: both atoms must belong to the same object;" + " did you merge the ligand with your protein?" + ) + + def covalentLinkCreate(self, widget): + if self.covLinkAtomSpec is not None: + imol = self.covLinkAtomSpec[0] + atom1 = self.covLinkAtomSpec[1][1:] + atom2 = self.covLinkAtomSpec[2][1:] + residue_1 = self.covLinkAtomSpec[3] + residue_2 = self.covLinkAtomSpec[4] + coot.make_link(imol, atom1, atom2, residue_1 + "-" + residue_2, 1.7) + coot.generic_object_clear(self.covLinkObject) + self.start_refinement() + else: + print("error: no covalent link defined") + + def set_selection_mode(self, widget): + self.selection_mode = widget.get_active_text() + + def get_samples_to_look_at(self, widget): + if self.selection_mode == "": + self.status_label.set_text("select model stage") + return + self.status_label.set_text("checking datasource for samples... ") + # first remove old samples if present + if len(self.Todo) != 0: + for n, item in enumerate(self.Todo): + self.cb.remove_text(0) + self.Todo = [] + self.siteDict = {} + self.Todo, self.siteDict = self.db.get_todoList_for_coot(self.selection_mode) + self.status_label.set_text("found {0!s} samples".format(len(self.Todo))) + # refresh sample CB + for item in sorted(self.Todo): + self.cb.append_text("{0!s}".format(item[0])) + if self.siteDict == {}: + self.cb_site.set_sensitive(False) + self.PREVbuttonSite.set_sensitive(False) + self.NEXTbuttonSite.set_sensitive(False) + else: + self.cb_site.set_sensitive(True) + self.PREVbuttonSite.set_sensitive(True) + self.NEXTbuttonSite.set_sensitive(True) + + def update_plot(self, refinement_cycle, Rfree, Rcryst): + fig = Figure(figsize=(2, 2), dpi=50) + Plot = fig.add_subplot(111) + Plot.set_ylim([0, max(Rcryst + Rfree)]) + Plot.set_xlabel("Refinement Cycle", fontsize=12) + Plot.plot(refinement_cycle, Rfree, label="Rfree", linewidth=2) + Plot.plot(refinement_cycle, Rcryst, label="Rcryst", linewidth=2) + Plot.legend( + bbox_to_anchor=(0.0, 1.02, 1.0, 0.102), + loc=3, + ncol=2, + mode="expand", + borderaxespad=0.0, + fontsize=12, + ) + return fig + + def place_ligand_here(self, widget): + cpd = str(self.select_cpd_cb.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if molName == cpd: + print("===> XCE: moving ligand to pointer") + coot_utils_XChem.move_molecule_here(imol) + print("LIGAND: ", molName) + + def merge_ligand_into_protein(self, widget): + cpd = str(self.select_cpd_cb.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if molName == cpd: + print("===> XCE: merge ligand into protein structure -->", cpd) + coot.merge_molecules_py([imol], self.mol_dict["protein"]) + if "rhofit" in coot.molecule_name( + imol + ) or "phenix" in coot.molecule_name(imol): + molName = ( + coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ] + .replace(".pdb", "") + .replace("_phenix", "") + .replace("_rhofit", "") + ) + if os.path.isfile( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ): + os.system( + "/bin/rm %s" + % os.path.join( + self.project_directory, + self.xtalID, + self.compoundID + ".cif", + ) + ) + print( + "XCE: changing directory", + os.path.join(self.project_directory, self.xtalID), + ) + os.chdir(os.path.join(self.project_directory, self.xtalID)) + print( + "XCE: changing symlink ln -s %s %s.cif" + % (os.path.join("compound", molName + ".cif"), self.compoundID) + ) + os.system( + "ln -s %s %s.cif" + % (os.path.join("compound", molName + ".cif"), self.compoundID) + ) + if os.path.isfile( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ) + ): + os.system( + "/bin/rm %s" + % os.path.join( + self.project_directory, + self.xtalID, + self.compoundID + ".pdb", + ) + ) + print( + "XCE: changing directory", + os.path.join(self.project_directory, self.xtalID), + ) + os.chdir(os.path.join(self.project_directory, self.xtalID)) + print( + "XCE: changing symlink ln -s %s %s.pdb" + % (os.path.join("compound", molName + ".pdb"), self.compoundID) + ) + os.system( + "ln -s %s %s.pdb" + % (os.path.join("compound", molName + ".pdb"), self.compoundID) + ) + print("===> XCE: deleting ligand molecule", molName) + coot.close_molecule(imol) + + self.select_cpd_cb.set_sensitive(False) + + def show_molprobity_to_do(self, widget): + print(self.panddaSerial) + print( + "==> XCE COOT: trying to find " + + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + + str(self.Serial - 1) + + "-report/molprobe/molprobity_coot.py", + ) + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + + str(self.Serial - 1) + + "-report/molprobe/molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + + str(self.Serial - 1) + + "-report/molprobe/molprobity_coot.py", + ) + ) + else: + print( + "==> XCE: cannot find " + + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + + def show_ground_state_mean_map(self, widget): + if widget.get_label().startswith("Show"): + loaded = False + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 1) + loaded = True + break + if not loaded: + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map(self.ground_state_mean_map, 0) + coot.set_last_map_colour(0.6, 0.6, 0) + widget.set_label("Undisplay ground state mean map") + else: + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 0) + widget.set_label("Show ground state mean map") + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import coot_utils_XChem + from xce.lib import XChemDB + from xce.lib import XChemLog + from xce.lib import XChemRefine + from xce.lib import XChemUtils + from xce.lib.cluster.slurm import get_token, fetch_password_gtk + + GUI().StartGUI() diff --git a/coot/XChemCootNew.py b/coot/XChemCootNew.py new file mode 100755 index 00000000..226608fb --- /dev/null +++ b/coot/XChemCootNew.py @@ -0,0 +1,1883 @@ +import sys +import getpass +import glob +import os +import pickle +from datetime import datetime + +import coot +import gobject +import gtk +from matplotlib.figure import Figure + +# had to adapt the original coot_utils.py file +# otherwise unable to import the original file without complaints about missing modules +# etc. +# modified file is now in $XChemExplorer_DIR/lib + + +class GUI(object): + """ + main class which opens the actual GUI + """ + + def __init__(self): + ################################################################################ + # read in settings file from XChemExplorer to set the relevant paths + self.settings = pickle.load(open(".xce_settings.pkl", "rb")) + + self.database_directory = self.settings["database_directory"] + self.xce_logfile = self.settings["xce_logfile"] + self.Logfile = XChemLog.updateLog(self.xce_logfile) + self.Logfile.insert("==> COOT: starting coot plugin...") + self.data_source = self.settings["data_source"] + self.db = XChemDB.data_source(self.data_source) + + print(self.settings) + + # checking for external software packages + self.external_software = XChemUtils.external_software(self.xce_logfile).check() + + self.selection_criteria = [ + "0 - All Datasets", + "1 - Analysis Pending", + "2 - PANDDA model", + "3 - In Refinement", + "4 - CompChem ready", + "5 - Deposition ready", + "6 - Deposited", + "7 - Analysed & Rejected", + ] + + self.experiment_stage = [ + ["Review PANDDA export", "2 - PANDDA model", 65000, 0, 0], + ["In Refinement", "3 - In Refinement", 65000, 0, 0], + ["Comp Chem Ready!", "4 - CompChem ready", 65000, 0, 0], + ["Ready for Deposition!", "5 - Deposition ready", 65000, 0, 0], + ["In PDB", "6 - Deposited", 65000, 0, 0], + ["Analysed & Rejected", "7 - Analysed & Rejected", 65000, 0, 0], + ] + + self.ligand_confidence_category = [ + "0 - no ligand present", + "1 - Low Confidence", + "2 - Correct ligand, weak density", + "3 - Clear density, unexpected ligand", + "4 - High Confidence", + ] + + # this decides which samples will be looked at + self.selection_mode = "" + self.pandda_index = -1 # refers to the number of sites + self.site_index = "0" + self.event_index = "0" + + # the Folder is kind of a legacy thing because my inital idea was to have + # separate folders for Data Processing and Refinement + self.project_directory = self.settings["initial_model_directory"] + self.Serial = 0 + self.panddaSerial = 0 + self.Refine = None + self.index = -1 + self.Todo = [] + self.siteDict = {} + + self.xtalID = "" + self.compoundID = "" + self.ground_state_mean_map = "" + self.spider_plot = "" + self.ligand_confidence = "" + self.refinementProtocol = "pandda_refmac" + + self.pdb_style = "refine.pdb" + self.mtz_style = "refine.mtz" + + self.covLinkObject = coot.new_generic_object_number("covalent bond") + self.covLinkAtomSpec = None + + self.label = None + + # stores imol of currently loaded molecules and maps + self.mol_dict = { + "protein": -1, + "ligand": -1, + "2fofc": -1, + "fofc": -1, + "event": -1, + "ligand_stereo": [], + } + + # two dictionaries which are flushed when a new crystal is loaded + # and which contain information to update the data source if necessary + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + + self.label_button_list = [] + + ################################################################################ + # some COOT settings + coot.set_map_radius(17) + coot.set_colour_map_rotation_for_map(0) + + self.QualityIndicators = { + "RefinementRcryst": "-", + "RefinementRfree": "-", + "RefinementRfreeTraficLight": "gray", + "RefinementResolution": "-", + "RefinementResolutionTL": "gray", + "RefinementMolProbityScore": "-", + "RefinementMolProbityScoreTL": "gray", + "RefinementRamachandranOutliers": "-", + "RefinementRamachandranOutliersTL": "gray", + "RefinementRamachandranFavored": "-", + "RefinementRamachandranFavoredTL": "gray", + "RefinementRmsdBonds": "-", + "RefinementRmsdBondsTL": "gray", + "RefinementRmsdAngles": "-", + "RefinementRmsdAnglesTL": "gray", + "RefinementMatrixWeight": "-", + } + + self.spider_plot_data = { + "PANDDA_site_ligand_id": "-", + "PANDDA_site_occupancy": "-", + "PANDDA_site_B_average": "-", + "PANDDA_site_B_ratio_residue_surroundings": "-", + "PANDDA_site_RSCC": "-", + "PANDDA_site_rmsd": "-", + "PANDDA_site_RSR": "-", + "PANDDA_site_RSZD": "-", + } + + # default refmac parameters + self.RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + "WATER": "", + "LIGOCC": "", + "SANITY": "", + } + + def StartGUI(self): + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_default_size(400, 800) + self.window.set_title("XChemExplorer") + self.vbox = gtk.VBox() # this is the main container + + ################################################################################ + # --- Sample Selection --- + + frame = gtk.Frame(label="Select Samples") + self.hbox_select_samples = gtk.HBox() + + self.cb_select_samples = gtk.combo_box_new_text() + self.cb_select_samples.connect("changed", self.set_selection_mode) + for citeria in self.selection_criteria: + self.cb_select_samples.append_text(citeria) + self.hbox_select_samples.add(self.cb_select_samples) + + self.select_samples_button = gtk.Button(label="GO") + self.select_samples_button.connect("clicked", self.get_samples_to_look_at) + self.hbox_select_samples.add(self.select_samples_button) + frame.add(self.hbox_select_samples) + self.vbox.pack_start(frame) + + ################################################################################ + # --- status window --- + frame = gtk.Frame() + self.status_label = gtk.Label() + frame.add(self.status_label) + self.vbox.pack_start(frame) + + ################################################################################ + # --- refinement protocol --- + frame = gtk.Frame() + self.refinementProtocolcheckbox = gtk.CheckButton("PanDDA model refinement)") + # callback is defined later + self.refinementProtocolcheckbox.set_active(True) + frame.add(self.refinementProtocolcheckbox) + self.vbox.pack_start(frame) + + ################################################################################ + # --- Refinement Statistics --- + # next comes a section which displays some global quality indicators + # a combination of labels and textview widgets, arranged in a table + + RRfreeLabel_frame = gtk.Frame() + self.RRfreeLabel = gtk.Label("R/Rfree") + RRfreeLabel_frame.add(self.RRfreeLabel) + self.RRfreeValue = gtk.Label( + self.QualityIndicators["RefinementRcryst"] + + "/" + + self.QualityIndicators["RefinementRfree"] + ) + RRfreeBox_frame = gtk.Frame() + self.RRfreeBox = gtk.EventBox() + self.RRfreeBox.add(self.RRfreeValue) + RRfreeBox_frame.add(self.RRfreeBox) + + ResolutionLabel_frame = gtk.Frame() + self.ResolutionLabel = gtk.Label("Resolution") + ResolutionLabel_frame.add(self.ResolutionLabel) + self.ResolutionValue = gtk.Label(self.QualityIndicators["RefinementResolution"]) + ResolutionBox_frame = gtk.Frame() + self.ResolutionBox = gtk.EventBox() + self.ResolutionBox.add(self.ResolutionValue) + ResolutionBox_frame.add(self.ResolutionBox) + + MolprobityScoreLabel_frame = gtk.Frame() + self.MolprobityScoreLabel = gtk.Label("MolprobityScore") + MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) + self.MolprobityScoreValue = gtk.Label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + MolprobityScoreBox_frame = gtk.Frame() + self.MolprobityScoreBox = gtk.EventBox() + self.MolprobityScoreBox.add(self.MolprobityScoreValue) + MolprobityScoreBox_frame.add(self.MolprobityScoreBox) + + RamachandranOutliersLabel_frame = gtk.Frame() + self.RamachandranOutliersLabel = gtk.Label("Rama Outliers") + RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) + self.RamachandranOutliersValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + RamachandranOutliersBox_frame = gtk.Frame() + self.RamachandranOutliersBox = gtk.EventBox() + self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) + RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) + + RamachandranFavoredLabel_frame = gtk.Frame() + self.RamachandranFavoredLabel = gtk.Label("Rama Favored") + RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) + self.RamachandranFavoredValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + RamachandranFavoredBox_frame = gtk.Frame() + self.RamachandranFavoredBox = gtk.EventBox() + self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) + RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) + + rmsdBondsLabel_frame = gtk.Frame() + self.rmsdBondsLabel = gtk.Label("rmsd(Bonds)") + rmsdBondsLabel_frame.add(self.rmsdBondsLabel) + self.rmsdBondsValue = gtk.Label(self.QualityIndicators["RefinementRmsdBonds"]) + rmsdBondsBox_frame = gtk.Frame() + self.rmsdBondsBox = gtk.EventBox() + self.rmsdBondsBox.add(self.rmsdBondsValue) + rmsdBondsBox_frame.add(self.rmsdBondsBox) + + rmsdAnglesLabel_frame = gtk.Frame() + self.rmsdAnglesLabel = gtk.Label("rmsd(Angles)") + rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) + self.rmsdAnglesValue = gtk.Label(self.QualityIndicators["RefinementRmsdAngles"]) + rmsdAnglesBox_frame = gtk.Frame() + self.rmsdAnglesBox = gtk.EventBox() + self.rmsdAnglesBox.add(self.rmsdAnglesValue) + rmsdAnglesBox_frame.add(self.rmsdAnglesBox) + + MatrixWeightLabel_frame = gtk.Frame() + self.MatrixWeightLabel = gtk.Label("Matrix Weight") + MatrixWeightLabel_frame.add(self.MatrixWeightLabel) + self.MatrixWeightValue = gtk.Label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + MatrixWeightBox_frame = gtk.Frame() + self.MatrixWeightBox = gtk.EventBox() + self.MatrixWeightBox.add(self.MatrixWeightValue) + MatrixWeightBox_frame.add(self.MatrixWeightBox) + + ligandIDLabel_frame = gtk.Frame() + self.ligandIDLabel = gtk.Label("Ligand ID") + ligandIDLabel_frame.add(self.ligandIDLabel) + self.ligandIDValue = gtk.Label(self.spider_plot_data["PANDDA_site_ligand_id"]) + ligandIDBox_frame = gtk.Frame() + self.ligandIDBox = gtk.EventBox() + self.ligandIDBox.add(self.ligandIDValue) + ligandIDBox_frame.add(self.ligandIDBox) + + ligand_occupancyLabel_frame = gtk.Frame() + self.ligand_occupancyLabel = gtk.Label("occupancy") + ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) + self.ligand_occupancyValue = gtk.Label( + self.spider_plot_data["PANDDA_site_occupancy"] + ) + ligand_occupancyBox_frame = gtk.Frame() + self.ligand_occupancyBox = gtk.EventBox() + self.ligand_occupancyBox.add(self.ligand_occupancyValue) + ligand_occupancyBox_frame.add(self.ligand_occupancyBox) + + ligand_BaverageLabel_frame = gtk.Frame() + self.ligand_BaverageLabel = gtk.Label("B average") + ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) + self.ligand_BaverageValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_average"] + ) + ligand_BaverageBox_frame = gtk.Frame() + self.ligand_BaverageBox = gtk.EventBox() + self.ligand_BaverageBox.add(self.ligand_BaverageValue) + ligand_BaverageBox_frame.add(self.ligand_BaverageBox) + + ligand_BratioSurroundingsLabel_frame = gtk.Frame() + self.ligand_BratioSurroundingsLabel = gtk.Label("B ratio") + ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) + self.ligand_BratioSurroundingsValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_ratio_residue_surroundings"] + ) + ligand_BratioSurroundingsBox_frame = gtk.Frame() + self.ligand_BratioSurroundingsBox = gtk.EventBox() + self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) + ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) + + ligand_RSCCLabel_frame = gtk.Frame() + self.ligand_RSCCLabel = gtk.Label("RSCC") + ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) + self.ligand_RSCCValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSCC"]) + ligand_RSCCBox_frame = gtk.Frame() + self.ligand_RSCCBox = gtk.EventBox() + self.ligand_RSCCBox.add(self.ligand_RSCCValue) + ligand_RSCCBox_frame.add(self.ligand_RSCCBox) + + ligand_rmsdLabel_frame = gtk.Frame() + self.ligand_rmsdLabel = gtk.Label("rmsd") + ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) + self.ligand_rmsdValue = gtk.Label(self.spider_plot_data["PANDDA_site_rmsd"]) + ligand_rmsdBox_frame = gtk.Frame() + self.ligand_rmsdBox = gtk.EventBox() + self.ligand_rmsdBox.add(self.ligand_rmsdValue) + ligand_rmsdBox_frame.add(self.ligand_rmsdBox) + + ligand_RSRLabel_frame = gtk.Frame() + self.ligand_RSRLabel = gtk.Label("RSR") + ligand_RSRLabel_frame.add(self.ligand_RSRLabel) + self.ligand_RSRValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSR"]) + ligand_RSRBox_frame = gtk.Frame() + self.ligand_RSRBox = gtk.EventBox() + self.ligand_RSRBox.add(self.ligand_RSRValue) + ligand_RSRBox_frame.add(self.ligand_RSRBox) + + ligand_RSZDLabel_frame = gtk.Frame() + self.ligand_RSZDLabel = gtk.Label("RSZD") + ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) + self.ligand_RSZDValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSZD"]) + ligand_RSZDBox_frame = gtk.Frame() + self.ligand_RSZDBox = gtk.EventBox() + self.ligand_RSZDBox.add(self.ligand_RSZDValue) + ligand_RSZDBox_frame.add(self.ligand_RSZDBox) + + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame() + self.table_left = gtk.Table(8, 2, False) + self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) + self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) + self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) + self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) + self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) + self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) + self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) + self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) + self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) + self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) + self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) + self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) + self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) + self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) + self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) + self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) + frame.add(self.table_left) + hbox.add(frame) + + frame = gtk.Frame() + self.table_right = gtk.Table(8, 2, False) + self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) + self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) + self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) + self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) + self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) + self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) + self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) + self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) + self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) + self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) + self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) + self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) + self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) + self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) + frame.add(self.table_right) + hbox.add(frame) + + outer_frame.add(hbox) + self.vbox.add(outer_frame) + + hbox = gtk.HBox() + button = gtk.Button(label="Show MolProbity to-do list") + button.connect("clicked", self.show_molprobity_to_do) + hbox.add(button) + # --- ground state mean map --- + self.ground_state_mean_map_button = gtk.Button( + label="Show ground state mean map" + ) + self.ground_state_mean_map_button.connect( + "clicked", self.show_ground_state_mean_map + ) + hbox.add(self.ground_state_mean_map_button) + self.vbox.add(hbox) + + self.vbox.pack_start(frame) + + ################################################################################ + # --- hbox for compound picture & spider_plot (formerly: refinement history) --- + frame = gtk.Frame() + self.hbox_for_info_graphics = gtk.HBox() + + # --- compound picture --- + compound_frame = gtk.Frame() + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image = gtk.Image() + self.image.set_from_pixbuf(self.pic) + compound_frame.add(self.image) + self.hbox_for_info_graphics.add(compound_frame) + + # --- Spider Plot --- + spider_plot_frame = gtk.Frame() + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image = gtk.Image() + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + spider_plot_frame.add(self.spider_plot_image) + self.hbox_for_info_graphics.add(spider_plot_frame) + + frame.add(self.hbox_for_info_graphics) + self.vbox.add(frame) + + ################################################################################ + outer_frame = gtk.Frame(label="Sample Navigator") + hboxSample = gtk.HBox() + + # --- crystal navigator combobox --- + frame = gtk.Frame() + self.vbox_sample_navigator = gtk.VBox() + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseXtal) + self.vbox_sample_navigator.add(self.cb) + # --- crystal navigator backward/forward button --- + self.PREVbutton = gtk.Button(label="<<<") + self.NEXTbutton = gtk.Button(label=">>>") + self.PREVbutton.connect("clicked", self.ChangeXtal, -1) + self.NEXTbutton.connect("clicked", self.ChangeXtal, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbutton) + hbox.pack_start(self.NEXTbutton) + self.vbox_sample_navigator.add(hbox) + frame.add(self.vbox_sample_navigator) + hboxSample.add(frame) + + # --- site navigator combobox --- + frame = gtk.Frame() + self.vbox_site_navigator = gtk.VBox() + self.cb_site = gtk.combo_box_new_text() + self.cb_site.connect("changed", self.ChooseSite) + self.vbox_site_navigator.add(self.cb_site) + # --- site navigator backward/forward button --- + self.PREVbuttonSite = gtk.Button(label="<<<") + self.NEXTbuttonSite = gtk.Button(label=">>>") + self.PREVbuttonSite.connect("clicked", self.ChangeSite, -1) + self.NEXTbuttonSite.connect("clicked", self.ChangeSite, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbuttonSite) + hbox.pack_start(self.NEXTbuttonSite) + self.vbox_site_navigator.add(hbox) + frame.add(self.vbox_site_navigator) + hboxSample.add(frame) + + outer_frame.add(hboxSample) + self.vbox.add(outer_frame) + + ################################################################################ + # --- current refinement stage --- + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame(label="Analysis Status") + vbox = gtk.VBox() + self.experiment_stage_button_list = [] + for n, button in enumerate(self.experiment_stage): + if n == 0: + new_button = gtk.RadioButton(None, button[0]) + else: + new_button = gtk.RadioButton(new_button, button[0]) + new_button.connect( + "toggled", self.experiment_stage_button_clicked, button[1] + ) + vbox.pack_start(new_button, False, False, 0) + self.experiment_stage_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + # --- ligand confidence --- + frame = gtk.Frame(label="Ligand Confidence") + vbox = gtk.VBox() + self.ligand_confidence_button_list = [] + for n, criteria in enumerate(self.ligand_confidence_category): + if n == 0: + new_button = gtk.RadioButton(None, criteria) + else: + new_button = gtk.RadioButton(new_button, criteria) + new_button.connect( + "toggled", self.ligand_confidence_button_clicked, criteria + ) + vbox.pack_start(new_button, False, False, 0) + self.ligand_confidence_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + outer_frame.add(hbox) + self.vbox.pack_start(outer_frame) + + # --- ligand modeling --- + frame = gtk.Frame(label="Ligand Modeling") + self.hbox_for_modeling = gtk.HBox() + self.merge_ligand_button = gtk.Button(label="Merge Ligand") + self.place_ligand_here_button = gtk.Button(label="Place Ligand here") + self.hbox_for_modeling.add(self.place_ligand_here_button) + self.place_ligand_here_button.connect("clicked", self.place_ligand_here) + self.hbox_for_modeling.add(self.merge_ligand_button) + self.merge_ligand_button.connect("clicked", self.merge_ligand_into_protein) + self.select_cpd_cb = gtk.combo_box_new_text() + self.select_cpd_cb.connect("changed", self.select_cpd) + self.hbox_for_modeling.add(self.select_cpd_cb) + frame.add(self.hbox_for_modeling) + self.vbox.pack_start(frame) + + # --- refinement & options --- + self.hbox_for_refinement = gtk.HBox() + self.REFINEbutton = gtk.Button(label="Refine") + self.RefinementParamsButton = gtk.Button(label="refinement parameters") + self.covalentLinksbutton = gtk.Button(label="covalent links\n-define-") + self.covalentLinksCreatebutton = gtk.Button( + label="covalent links\n-create & refine-" + ) + self.REFINEbutton.connect("clicked", self.REFINE) + self.hbox_for_refinement.add(self.REFINEbutton) + self.RefinementParamsButton.connect("clicked", self.RefinementParams) + self.covalentLinksbutton.connect("clicked", self.covalentLinkDef) + self.covalentLinksCreatebutton.connect("clicked", self.covalentLinkCreate) + self.hbox_for_refinement.add(self.RefinementParamsButton) + self.hbox_for_refinement.add(self.covalentLinksbutton) + self.hbox_for_refinement.add(self.covalentLinksCreatebutton) + self.vbox.add(self.hbox_for_refinement) + + # need to put it here, because attributes within refinementProtocolCallback + # function are defined after checkbox is defined + self.refinementProtocolcheckbox.connect( + "toggled", self.refinementProtocolCallback + ) + + # --- CANCEL button --- + self.CANCELbutton = gtk.Button(label="CANCEL") + self.CANCELbutton.connect("clicked", self.CANCEL) + self.vbox.add(self.CANCELbutton) + + self.window.add(self.vbox) + self.window.show_all() + + def CANCEL(self, widget): + self.window.destroy() + + def ChangeXtal(self, widget, data=None): + self.index = self.index + data + if self.index < 0: + self.index = 0 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def ChooseXtal(self, widget): + self.xtalID = str(widget.get_active_text()) + for n, item in enumerate(self.Todo): + if str(item[0]) == self.xtalID: + self.index = n + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + + self.refresh_site_combobox() + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + if str(self.Todo[self.index][0]) is not None: + self.compoundID = str(self.Todo[self.index][1]) + self.refinement_outcome = str(self.Todo[self.index][5]) + self.update_RefinementOutcome_radiobutton() + if ( + self.xtalID not in self.siteDict + ): # i.e. we are not working with a PanDDA model + self.ligand_confidence = str(self.Todo[self.index][6]) + + self.RefreshData() + + def select_cpd(self, widget): + cpd = str(widget.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if "rhofit" in coot.molecule_name(imol) or "phenix" in coot.molecule_name( + imol + ): + molNameCIF = ( + coot.molecule_name(imol)[coot.molecule_name(imol).rfind("/") + 1 :] + .replace(".pdb", "") + .replace("_phenix", "") + .replace("_rhofit", "") + ) + else: + molNameCIF = molName + print(cpd, "-", imol, "-", coot.molecule_name(imol)) + if molName == cpd: + coot.set_mol_displayed(imol, 1) + print( + "reading", + os.path.join( + self.project_directory, + self.xtalID, + "compound", + molNameCIF + ".cif", + ), + ) + coot.read_cif_dictionary( + os.path.join( + self.project_directory, + self.xtalID, + "compound", + molNameCIF + ".cif", + ) + ) + else: + coot.set_mol_displayed(imol, 0) + + def update_RefinementOutcome_radiobutton(self): + # updating dataset outcome radiobuttons + current_stage = 0 + for i, entry in enumerate(self.experiment_stage): + if entry[1].split()[0] == self.refinement_outcome.split()[0]: + current_stage = i + break + for i, button in enumerate(self.experiment_stage_button_list): + if i == current_stage: + button.set_active(True) + break + + def update_LigandConfidence_radiobutton(self): + # updating ligand confidence radiobuttons + current_stage = 0 + for i, entry in enumerate(self.ligand_confidence_category): + print("--->", entry, self.ligand_confidence) + try: + if entry.split()[0] == self.ligand_confidence.split()[0]: + current_stage = i + break + except IndexError: + pass + for i, button in enumerate(self.ligand_confidence_button_list): + if i == current_stage: + button.set_active(True) + break + + def refresh_site_combobox(self): + # reset self.pandda_index + self.pandda_index = -1 + # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever + # be 100 sites + for n in range(-1, 100): + self.cb_site.remove_text(0) + self.site_index = "0" + self.event_index = "0" + # only repopulate if site exists + if self.xtalID in self.siteDict: + for item in sorted(self.siteDict[self.xtalID]): + self.cb_site.append_text( + "site: {0!s} - event: {1!s}".format(item[5], item[6]) + ) + + def ChangeSite(self, widget, data=None): + if self.xtalID in self.siteDict: + self.pandda_index = self.pandda_index + data + if self.pandda_index < 0: + self.pandda_index = 0 + if self.pandda_index >= len(self.siteDict[self.xtalID]): + self.pandda_index = 0 + self.cb_site.set_active(self.pandda_index) + + def ChooseSite(self, widget): + tmp = str(widget.get_active_text()) + print(self.siteDict) + print(self.site_index) + self.site_index = tmp.split()[1] + self.event_index = tmp.split()[4] + for n, item in enumerate(self.siteDict[self.xtalID]): + if item[5] == self.site_index and item[6] == self.event_index: + self.pandda_index = n + self.RefreshSiteData() + + def RefreshSiteData(self): + if self.pandda_index == -1: + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + else: + self.merge_ligand_button.set_sensitive(False) + self.place_ligand_here_button.set_sensitive(False) + # and remove ligand molecule so that there is no temptation to merge it + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if self.compoundID + ".pdb" in coot.molecule_name(imol): + coot.close_molecule(imol) + + print("pandda index", self.pandda_index) + self.spider_plot = self.siteDict[self.xtalID][self.pandda_index][4] + print("new spider plot:", self.spider_plot) + self.event_map = self.siteDict[self.xtalID][self.pandda_index][0] + print("new event map:", self.event_map) + self.ligand_confidence = str(self.siteDict[self.xtalID][self.pandda_index][7]) + self.update_LigandConfidence_radiobutton() + site_x = float(self.siteDict[self.xtalID][self.pandda_index][1]) + site_y = float(self.siteDict[self.xtalID][self.pandda_index][2]) + site_z = float(self.siteDict[self.xtalID][self.pandda_index][3]) + print("new site coordinates:", site_x, site_y, site_z) + coot.set_rotation_centre(site_x, site_y, site_z) + + self.spider_plot_data = ( + self.db.get_db_pandda_dict_for_sample_and_site_and_event( + self.xtalID, self.site_index, self.event_index + ) + ) + print(">>>>> spider plot data", self.spider_plot_data) + self.ligandIDValue.set_label(self.spider_plot_data["PANDDA_site_ligand_id"]) + try: + self.ligand_occupancyValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_occupancy"]), 2)) + ) + except ValueError: + self.ligand_occupancyValue.set_label("-") + + try: + self.ligand_BaverageValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_B_average"]), 2)) + ) + except ValueError: + self.ligand_BaverageValue.set_label("-") + + try: + self.ligand_BratioSurroundingsValue.set_label( + str( + round( + float( + self.spider_plot_data[ + "PANDDA_site_B_ratio_residue_surroundings" + ] + ), + 2, + ) + ) + ) + except ValueError: + self.ligand_BratioSurroundingsValue.set_label("-") + + try: + self.ligand_RSCCValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSCC"]), 2)) + ) + except ValueError: + self.ligand_RSCCValue.set_label("-") + + try: + self.ligand_rmsdValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_rmsd"]), 2)) + ) + except ValueError: + self.ligand_rmsdValue.set_label("-") + + try: + self.ligand_RSRValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSR"]), 2)) + ) + except ValueError: + self.ligand_RSRValue.set_label("-") + + try: + self.ligand_RSZDValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSZD"]), 2)) + ) + except ValueError: + self.ligand_RSZDValue.set_label("-") + + ################################################################################ + # delete old Event MAPs + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if "map.native.ccp4" in coot.molecule_name(imol): + coot.close_molecule(imol) + + ################################################################################ + # Spider plot + # Note: refinement history was shown instead previously + if os.path.isfile(self.spider_plot): + spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) + else: + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + ################################################################################ + # check for PANDDAs EVENT maps + if os.path.isfile(self.event_map): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.handle_read_ccp4_map((self.event_map), 0) + for imol in coot_utils_XChem.molecule_number_list(): + if self.event_map in coot.molecule_name(imol): + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + + def experiment_stage_button_clicked(self, widget, data=None): + self.db_dict_mainTable["RefinementOutcome"] = data + self.db_dict_mainTable["RefinementOutcomePerson"] = getpass.getuser() + self.db_dict_mainTable["RefinementOutcomeDate"] = datetime.strftime( + datetime.now(), "%Y-%m-%d_%H-%M-%S.%f" + )[:-4] + self.Logfile.insert( + "==> COOT: setting Refinement Outcome for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.create_or_remove_missing_records_in_depositTable( + self.xce_logfile, self.xtalID, "ligand_bound", self.db_dict_mainTable + ) + + def ligand_confidence_button_clicked(self, widget, data=None): + print("PANDDA_index", self.pandda_index) + if self.pandda_index == -1: + self.db_dict_mainTable["RefinementLigandConfidence"] = data + self.Logfile.insert( + "==> COOT: setting Ligand Confidence for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.update_data_source(self.xtalID, self.db_dict_mainTable) + self.Todo[self.index][6] = data + else: + self.db_dict_panddaTable["PANDDA_site_confidence"] = data + self.Logfile.insert( + "==> COOT: setting Ligand Confidence for " + + self.xtalID + + " (site=" + + str(self.site_index) + + ", event=" + + str(self.event_index) + + ") to " + + str(data) + + " in panddaTable of datasource" + ) + self.db.update_site_event_panddaTable( + self.xtalID, self.site_index, self.event_index, self.db_dict_panddaTable + ) + self.siteDict[self.xtalID][self.pandda_index][7] = data + + def RefreshData(self): + # reset spider plot image + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + # reset ground state mean map + self.ground_state_mean_map = "" + self.ground_state_mean_map_button.set_sensitive(False) + self.ground_state_mean_map_button.set_label("Show ground state mean map") + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + ): + self.ground_state_mean_map_button.set_sensitive(True) + self.ground_state_mean_map = os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + + # initialize Refinement library + self.Refine = XChemRefine.Refine( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ) + self.Serial = XChemRefine.GetSerial(self.project_directory, self.xtalID) + self.panddaSerial = (4 - len(str(self.Serial))) * "0" + str(self.Serial) + if self.Serial == 1: + # i.e. no refinement has been done; data is probably straight out of dimple + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, self.pdb_style), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "init.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + + # all this information is now updated in the datasource after each refinement + # cycle + self.QualityIndicators = self.db.get_db_dict_for_sample(self.xtalID) + + ################################################################################ + # history + # if the structure was previously refined, try to read the parameters + if self.Serial > 1: + self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) + print("==> REFMAC params:", self.RefmacParams) + + ################################################################################ + # ligand files + # first remove old samples if present + print(">>>", self.mol_dict["ligand_stereo"]) + for n, item in enumerate(self.mol_dict["ligand_stereo"]): + print("__", item) + self.select_cpd_cb.remove_text(0) + print("done") + + ################################################################################ + # remove potential generic line which indicates a possible covalent link + coot.generic_object_clear(self.covLinkObject) + self.covLinkAtomSpec = None + + ################################################################################ + # update pdb & maps + + ################################################################################ + # delete old PDB and MAP files + # - get a list of all molecules which are currently opened in COOT + # - remove all molecules/ maps before loading a new set + if len(coot_utils_XChem.molecule_number_list()) > 0: + for item in coot_utils_XChem.molecule_number_list(): + coot.close_molecule(item) + + ################################################################################ + # read new PDB files + # read protein molecule after ligand so that this one is the active molecule + coot.set_nomenclature_errors_on_read("ignore") + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.compoundID + ".pdb") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ), + 0, + ) + self.mol_dict["ligand"] = imol + coot.read_cif_dictionary( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ) + self.select_cpd_cb.append_text(self.compoundID) + self.mol_dict["ligand_stereo"] = [] + self.mol_dict["ligand_stereo"].append(imol) + # ligands in compound directory + for cifFile in sorted( + glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + "compound", + self.compoundID + "_*.pdb", + ) + ) + ): + cif = cifFile[cifFile.rfind("/") + 1 :] + if "_with_H" in cif: + continue + self.select_cpd_cb.append_text(cif.replace(".pdb", "")) + imol = coot.handle_read_draw_molecule_with_recentre(cifFile, 0) + self.mol_dict["ligand_stereo"].append(imol) + coot.set_mol_displayed(imol, 0) + # autofitted ligands + for pdbFile in sorted( + glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + "autofit_ligand", + "*", + "*.pdb", + ) + ) + ): + autofitRun = pdbFile.split("/")[len(pdbFile.split("/")) - 2] + if pdbFile.endswith(autofitRun + ".pdb"): + self.select_cpd_cb.append_text(autofitRun) + imol = coot.handle_read_draw_molecule_with_recentre(pdbFile, 0) + self.mol_dict["ligand_stereo"].append(imol) + coot.set_mol_displayed(imol, 0) + self.select_cpd_cb.set_sensitive(True) + self.select_cpd_cb.set_active(0) + else: + print("no compound found in sample directory") + self.select_cpd_cb.set_sensitive(False) + + if not os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + + if self.refinementProtocol.startswith("pandda"): + self.Logfile.insert( + "==> COOT: looking for ground-state model " + + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.ground-state.pdb", + ) + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.ground-state.pdb", + ) + ): + self.Logfile.insert("==> COOT: found ground-state model") + os.chdir(os.path.join(self.project_directory, self.xtalID)) + coot.set_colour_map_rotation_on_read_pdb(0) + try: + color_wheel_rotation = 160 / float(imol + 2) + except UnboundLocalError: + color_wheel_rotation = 80 + coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.ground-state.pdb", + ), + 0, + ) + coot.set_colour_by_molecule(imol) + coot.set_mol_active(imol, 0) + else: + self.Logfile.error("==> COOT - cannot find ground-state model") + self.Logfile.insert( + "==> COOT: looking for bound-state model " + + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb", + ) + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb", + ) + ): + self.Logfile.insert("==> COOT: found bound-state model") + os.chdir(os.path.join(self.project_directory, self.xtalID)) + coot.set_colour_map_rotation_on_read_pdb(0) + color_wheel_rotation = 21 / float(imol + 2) + coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, + self.xtalID, + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb", + ), + 0, + ) + self.mol_dict["protein"] = imol + else: + self.Logfile.error("==> COOT: cannot find bound-state model") + self.Logfile.warning("==> COOT: moving to next crystal...") + self.go_to_next_xtal() + else: + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, self.pdb_style), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "init.pdb"), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), 0 + ) + else: + self.go_to_next_xtal() + self.mol_dict["protein"] = imol + + # read any one event map if present + for event_map in glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-event_*.native.ccp4", + ) + ): + coot.handle_read_ccp4_map((event_map), 0) + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + break + + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) or coot.molecule_name(item).endswith(self.pdb_style): + # master switch to show symmetry molecules + coot.set_show_symmetry_master(1) + coot.set_show_symmetry_molecule(item, 1) # show symm for model + + ################################################################################ + # read fofc maps + # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map + # read 2fofc map last so that one can change its contour level + # coot 0.9 does not handle P1 maps well, so now looking for non-existent map in + # order to trigger map calculation from mtz file + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "2fofc_??????.map") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.set_default_initial_contour_level_for_difference_map(3) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "fofc.map"), 1 + ) + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "2fofc.map"), 0 + ) + coot.set_last_map_colour(0, 0, 1) + else: + # try to open mtz file with same name as pdb file + coot.set_default_initial_contour_level_for_map(1) + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "init.mtz") + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ) + + ################################################################################ + # update Quality Indicator table + try: + self.RRfreeValue.set_label( + str(round(float(self.QualityIndicators["RefinementRcryst"]), 3)) + + " / " + + str(round(float(self.QualityIndicators["RefinementRfree"]), 3)) + ) + except ValueError: + self.RRfreeValue.set_label("-") + + try: + self.RRfreeBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRfreeTraficLight"] + ), + ) + except ValueError: + pass + self.ResolutionValue.set_label(self.QualityIndicators["RefinementResolution"]) + try: + self.ResolutionBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementResolutionTL"]), + ) + except ValueError: + pass + self.MolprobityScoreValue.set_label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + try: + self.MolprobityScoreBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementMolProbityScoreTL"] + ), + ) + except ValueError: + pass + self.RamachandranOutliersValue.set_label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + try: + self.RamachandranOutliersBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranOutliersTL"] + ), + ) + except ValueError: + pass + self.RamachandranFavoredValue.set_label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + try: + self.RamachandranFavoredBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranFavoredTL"] + ), + ) + except ValueError: + pass + self.rmsdBondsValue.set_label(self.QualityIndicators["RefinementRmsdBonds"]) + try: + self.rmsdBondsBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdBondsTL"]), + ) + except ValueError: + pass + self.rmsdAnglesValue.set_label(self.QualityIndicators["RefinementRmsdAngles"]) + try: + self.rmsdAnglesBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdAnglesTL"]), + ) + except ValueError: + pass + self.MatrixWeightValue.set_label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + + try: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".png" + ) + ) + except gobject.GError: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image.set_from_pixbuf(self.pic) + + def go_to_next_xtal(self): + self.index += 1 + if self.index >= len(self.Todo): + self.index = len(self.Todo) + self.cb.set_active(self.index) + + def REFINE(self, widget): + self.start_refinement() + + def start_refinement(self): + if self.refinementProtocol.startswith("pandda"): + ####################################################### + if not os.path.isdir( + os.path.join(self.project_directory, self.xtalID, "cootOut") + ): + os.mkdir(os.path.join(self.project_directory, self.xtalID, "cootOut")) + # create folder for new refinement cycle + try: + self.Logfile.insert( + "==> COOT: trying to make folder: %s" + % os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + ) + ) + os.mkdir( + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + ) + ) + except OSError: + self.Logfile.warning( + "==> COOT: folder exists; will overwrite contents!" + ) + self.Logfile.warning( + "==> COOT: it is advised to check the sample directory" + " as this might be a symptom for a PDB file problem" + ) + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ + # folder. note: the user has to make sure that the ligand file was merged + # into main file + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) or coot.molecule_name(item).endswith(self.pdb_style): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + "refine.modified.pdb", + ), + ) + break + + XChemRefine.panddaRefine( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ).RunQuickRefine( + self.Serial, + self.RefmacParams, + self.external_software, + self.xce_logfile, + self.refinementProtocol, + self.covLinkAtomSpec, + get_token(fetch_password_gtk), + ) + else: + ####################################################### + # create folder for new refinement cycle and check if free.mtz exists + if not os.path.isdir(os.path.join(self.project_directory, self.xtalID)): + os.mkdir(os.path.join(self.project_directory, self.xtalID)) + if not os.path.isdir( + os.path.join( + self.project_directory, self.xtalID, "Refine_" + str(self.Serial) + ) + ): + os.mkdir( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + ) + ) + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ + # folder. note: the user has to make sure that the ligand file was merged + # into main file + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith(self.pdb_style): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + elif coot.molecule_name(item).endswith("refine.split.bound-state.pdb"): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + elif coot.molecule_name(item).endswith("init.pdb"): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + elif coot.molecule_name(item).endswith("dimple.pdb"): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + + self.Refine.RunRefmac( + self.Serial, + self.RefmacParams, + self.external_software, + self.xce_logfile, + self.covLinkAtomSpec, + get_token(fetch_password_gtk), + ) + + self.index += 1 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def RefinementParams(self, widget): + print("\n==> XCE: changing refinement parameters") + self.RefmacParams = XChemRefine.RefineParams( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ).RefmacRefinementParams(self.RefmacParams) + + def covalentLinkDef(self, widget): + coot.user_defined_click_py(2, self.show_potential_link) + + def show_potential_link(self, *clicks): + # first find imol of protein molecule + # it's a prerequisite that the ligand is merged into the protein + imol_protein = None + for imol in coot_utils_XChem.molecule_number_list(): + print(">", coot.molecule_name(imol)) + if ( + coot.molecule_name(imol).endswith(self.pdb_style) + or coot.molecule_name(imol).endswith("init.pdb") + or coot.molecule_name(imol).endswith("dimple.pdb") + or coot.molecule_name(imol).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) + ): + imol_protein = imol + break + + print("please click on the two atoms you want to link") + if len(clicks) == 2: + click_1 = clicks[0] + click_2 = clicks[1] + imol_1 = click_1[1] + imol_2 = click_2[1] + print("imolp", imol, "imo11", imol_1, "imol2", imol_2) + if imol_1 == imol_2 and imol_1 == imol_protein: + print("click_1", click_1) + self.covLinkAtomSpec = None + xyz_1 = coot.atom_info_string_py( + click_1[1], + click_1[2], + click_1[3], + click_1[4], + click_1[5], + click_1[6], + ) + residue_1 = coot.residue_name( + click_1[1], click_1[2], click_1[3], click_1[4] + ) + xyz_2 = coot.atom_info_string_py( + click_2[1], + click_2[2], + click_2[3], + click_2[4], + click_2[5], + click_2[6], + ) + residue_2 = coot.residue_name( + click_2[1], click_2[2], click_2[3], click_2[4] + ) + thick = 4 + coot.to_generic_object_add_line( + self.covLinkObject, + "yellowtint", + thick, + xyz_1[3], + xyz_1[4], + xyz_1[5], + xyz_2[3], + xyz_2[4], + xyz_2[5], + ) + coot.set_display_generic_object(self.covLinkObject, 1) + self.covLinkAtomSpec = [ + imol_protein, + click_1, + click_2, + residue_1, + residue_2, + ] + else: + print( + "error: both atoms must belong to the same object;" + " did you merge the ligand with your protein?" + ) + + def covalentLinkCreate(self, widget): + if self.covLinkAtomSpec is not None: + imol = self.covLinkAtomSpec[0] + atom1 = self.covLinkAtomSpec[1][1:] + atom2 = self.covLinkAtomSpec[2][1:] + residue_1 = self.covLinkAtomSpec[3] + residue_2 = self.covLinkAtomSpec[4] + coot.make_link(imol, atom1, atom2, residue_1 + "-" + residue_2, 1.7) + coot.generic_object_clear(self.covLinkObject) + self.start_refinement() + else: + print("error: no covalent link defined") + + def set_selection_mode(self, widget): + self.selection_mode = widget.get_active_text() + + def get_samples_to_look_at(self, widget): + if self.selection_mode == "": + self.status_label.set_text("select model stage") + return + self.status_label.set_text("checking datasource for samples... ") + # first remove old samples if present + if len(self.Todo) != 0: + for n, item in enumerate(self.Todo): + self.cb.remove_text(0) + self.Todo = [] + self.siteDict = {} + self.Todo, self.siteDict = self.db.get_todoList_for_coot(self.selection_mode) + self.status_label.set_text("found {0!s} samples".format(len(self.Todo))) + # refresh sample CB + for item in sorted(self.Todo): + self.cb.append_text("{0!s}".format(item[0])) + if self.siteDict == {}: + self.cb_site.set_sensitive(False) + self.PREVbuttonSite.set_sensitive(False) + self.NEXTbuttonSite.set_sensitive(False) + else: + self.cb_site.set_sensitive(True) + self.PREVbuttonSite.set_sensitive(True) + self.NEXTbuttonSite.set_sensitive(True) + + def update_plot(self, refinement_cycle, Rfree, Rcryst): + fig = Figure(figsize=(2, 2), dpi=50) + Plot = fig.add_subplot(111) + Plot.set_ylim([0, max(Rcryst + Rfree)]) + Plot.set_xlabel("Refinement Cycle", fontsize=12) + Plot.plot(refinement_cycle, Rfree, label="Rfree", linewidth=2) + Plot.plot(refinement_cycle, Rcryst, label="Rcryst", linewidth=2) + Plot.legend( + bbox_to_anchor=(0.0, 1.02, 1.0, 0.102), + loc=3, + ncol=2, + mode="expand", + borderaxespad=0.0, + fontsize=12, + ) + return fig + + def place_ligand_here(self, widget): + cpd = str(self.select_cpd_cb.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if molName == cpd: + print("===> XCE: moving ligand to pointer") + coot_utils_XChem.move_molecule_here(imol) + print("LIGAND: ", molName) + + def merge_ligand_into_protein(self, widget): + cpd = str(self.select_cpd_cb.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if molName == cpd: + print("===> XCE: merge ligand into protein structure -->", cpd) + coot.merge_molecules_py([imol], self.mol_dict["protein"]) + if "rhofit" in coot.molecule_name( + imol + ) or "phenix" in coot.molecule_name(imol): + molName = ( + coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ] + .replace(".pdb", "") + .replace("_phenix", "") + .replace("_rhofit", "") + ) + if os.path.isfile( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ): + os.system( + "/bin/rm %s" + % os.path.join( + self.project_directory, + self.xtalID, + self.compoundID + ".cif", + ) + ) + print( + "XCE: changing directory", + os.path.join(self.project_directory, self.xtalID), + ) + os.chdir(os.path.join(self.project_directory, self.xtalID)) + print( + "XCE: changing symlink ln -s %s %s.cif" + % (os.path.join("compound", molName + ".cif"), self.compoundID) + ) + os.system( + "ln -s %s %s.cif" + % (os.path.join("compound", molName + ".cif"), self.compoundID) + ) + if os.path.isfile( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ) + ): + os.system( + "/bin/rm %s" + % os.path.join( + self.project_directory, + self.xtalID, + self.compoundID + ".pdb", + ) + ) + print( + "XCE: changing directory", + os.path.join(self.project_directory, self.xtalID), + ) + os.chdir(os.path.join(self.project_directory, self.xtalID)) + print( + "XCE: changing symlink ln -s %s %s.pdb" + % (os.path.join("compound", molName + ".pdb"), self.compoundID) + ) + os.system( + "ln -s %s %s.pdb" + % (os.path.join("compound", molName + ".pdb"), self.compoundID) + ) + print("===> XCE: deleting ligand molecule", molName) + coot.close_molecule(imol) + + self.select_cpd_cb.set_sensitive(False) + + def show_molprobity_to_do(self, widget): + print(self.panddaSerial) + AdjPanddaSerial = (4 - len(str(self.Serial))) * "0" + str( + int(self.panddaSerial) - 1 + ) + print( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.panddaSerial), + "molprobity_coot.py", + ) + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + elif os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(AdjPanddaSerial), + "molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(AdjPanddaSerial), + "molprobity_coot.py", + ) + ) + else: + print( + "==> XCE: cannot find " + + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + + def refinementProtocolCallback(self, widget): + if widget.get_active(): + if self.refinementProtocolcheckbox.get_active(): + self.refinementProtocol = "pandda_phenix" + else: + self.refinementProtocol = "pandda_refmac" + self.PREVbuttonSite.set_sensitive(True) + self.NEXTbuttonSite.set_sensitive(True) + else: + self.refinementProtocolcheckbox.set_active(False) + self.refinementProtocol = "refmac" + self.PREVbuttonSite.set_sensitive(False) + self.NEXTbuttonSite.set_sensitive(False) + print(self.refinementProtocol) + + def show_ground_state_mean_map(self, widget): + if widget.get_label().startswith("Show"): + loaded = False + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 1) + loaded = True + break + if not loaded: + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map(self.ground_state_mean_map, 0) + coot.set_last_map_colour(0.6, 0.6, 0) + widget.set_label("Undisplay ground state mean map") + else: + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 0) + widget.set_label("Show ground state mean map") + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import coot_utils_XChem + from xce.lib import XChemDB + from xce.lib import XChemLog + from xce.lib import XChemRefine + from xce.lib import XChemUtils + from xce.lib.cluster.slurm import get_token, fetch_password_gtk + + GUI().StartGUI() diff --git a/coot/XChemCootOld.py b/coot/XChemCootOld.py new file mode 100755 index 00000000..1583fd9a --- /dev/null +++ b/coot/XChemCootOld.py @@ -0,0 +1,1323 @@ +import sys +import os +import pickle + +import coot +import gobject +import gtk +from matplotlib.figure import Figure + +# had to adapt the original coot_utils.py file +# otherwise unable to import the original file without complaints about missing modules +# etc. +# modified file is now in $XChemExplorer_DIR/lib + + +class GUI(object): + """ + main class which opens the actual GUI + """ + + def __init__(self): + ################################################################################ + # read in settings file from XChemExplorer to set the relevant paths + print("current dir", os.getcwd()) + self.settings = pickle.load(open(".xce_settings.pkl", "rb")) + print("setting", self.settings) + self.database_directory = self.settings["database_directory"] + self.xce_logfile = self.settings["xce_logfile"] + self.data_source = self.settings["data_source"] + self.db = XChemDB.data_source(self.data_source) + + # checking for external software packages + self.external_software = XChemUtils.external_software(self.xce_logfile).check() + + self.selection_criteria = [ + "0 - All Datasets", + "1 - Analysis Pending", + "2 - PANDDA model", + "3 - In Refinement", + "4 - CompChem ready", + "5 - Deposition ready", + "6 - Deposited", + ] + + self.experiment_stage = [ + ["Review PANDDA export", "2 - PANDDA model", 65000, 0, 0], + ["In Refinement", "3 - In Refinement", 65000, 0, 0], + ["Comp Chem Ready!", "4 - CompChem ready", 65000, 0, 0], + ["Ready for Deposition!", "5 - Deposition ready", 65000, 0, 0], + ["In PDB", "6 - Deposited", 65000, 0, 0], + ] + + self.ligand_confidence_category = [ + "0 - no ligand present", + "1 - Low Confidence", + "2 - Correct ligand, weak density", + "3 - Clear density, unexpected ligand", + "4 - High Confidence", + ] + + # this decides which samples will be looked at + self.selection_mode = "" + self.pandda_index = -1 # refers to the number of sites + self.site_index = "0" + self.event_index = "0" + + # the Folder is kind of a legacy thing because my inital idea was to have + # separate folders for Data Processing and Refinement + self.project_directory = self.settings["initial_model_directory"] + self.Serial = 0 + self.Refine = None + self.index = -1 + self.Todo = [] + self.siteDict = {} + + self.xtalID = "" + self.compoundID = "" + self.spider_plot = "" + self.ligand_confidence = "" + + self.pdb_style = "refine.pdb" + self.mtz_style = "refine.mtz" + + # stores imol of currently loaded molecules and maps + self.mol_dict = { + "protein": -1, + "ligand": -1, + "2fofc": -1, + "fofc": -1, + "event": -1, + } + + # two dictionaries which are flushed when a new crystal is loaded + # and which contain information to update the data source if necessary + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + + ################################################################################ + # some COOT settings + coot.set_map_radius(15) + coot.set_colour_map_rotation_for_map(0) + coot.set_colour_map_rotation_on_read_pdb_flag(0) + + self.QualityIndicators = { + "RefinementRcryst": "-", + "RefinementRfree": "-", + "RefinementRfreeTraficLight": "gray", + "RefinementResolution": "-", + "RefinementResolutionTL": "gray", + "RefinementMolProbityScore": "-", + "RefinementMolProbityScoreTL": "gray", + "RefinementRamachandranOutliers": "-", + "RefinementRamachandranOutliersTL": "gray", + "RefinementRamachandranFavored": "-", + "RefinementRamachandranFavoredTL": "gray", + "RefinementRmsdBonds": "-", + "RefinementRmsdBondsTL": "gray", + "RefinementRmsdAngles": "-", + "RefinementRmsdAnglesTL": "gray", + "RefinementMatrixWeight": "-", + } + + self.spider_plot_data = { + "PANDDA_site_ligand_id": "-", + "PANDDA_site_occupancy": "-", + "PANDDA_site_B_average": "-", + "PANDDA_site_B_ratio_residue_surroundings": "-", + "PANDDA_site_RSCC": "-", + "PANDDA_site_rmsd": "-", + "PANDDA_site_RSR": "-", + "PANDDA_site_RSZD": "-", + } + + # default refmac parameters + self.RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + } + + def StartGUI(self): + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_default_size(400, 800) + self.window.set_title("XChemExplorer") + self.vbox = gtk.VBox() # this is the main container + + ################################################################################ + # --- Sample Selection --- + + frame = gtk.Frame(label="Select Samples") + self.hbox_select_samples = gtk.HBox() + + self.cb_select_samples = gtk.combo_box_new_text() + self.cb_select_samples.connect("changed", self.set_selection_mode) + for citeria in self.selection_criteria: + self.cb_select_samples.append_text(citeria) + self.hbox_select_samples.add(self.cb_select_samples) + + self.select_samples_button = gtk.Button(label="GO") + self.select_samples_button.connect("clicked", self.get_samples_to_look_at) + self.hbox_select_samples.add(self.select_samples_button) + frame.add(self.hbox_select_samples) + self.vbox.pack_start(frame) + + ################################################################################ + # --- status window --- + frame = gtk.Frame() + self.status_label = gtk.Label() + frame.add(self.status_label) + self.vbox.pack_start(frame) + + # SPACER + self.vbox.add(gtk.Label(" ")) + + ################################################################################ + # --- Refinement Statistics --- + # next comes a section which displays some global quality indicators + # a combination of labels and textview widgets, arranged in a table + + RRfreeLabel_frame = gtk.Frame() + self.RRfreeLabel = gtk.Label("R/Rfree") + RRfreeLabel_frame.add(self.RRfreeLabel) + self.RRfreeValue = gtk.Label( + self.QualityIndicators["RefinementRcryst"] + + "/" + + self.QualityIndicators["RefinementRfree"] + ) + RRfreeBox_frame = gtk.Frame() + self.RRfreeBox = gtk.EventBox() + self.RRfreeBox.add(self.RRfreeValue) + RRfreeBox_frame.add(self.RRfreeBox) + + ResolutionLabel_frame = gtk.Frame() + self.ResolutionLabel = gtk.Label("Resolution") + ResolutionLabel_frame.add(self.ResolutionLabel) + self.ResolutionValue = gtk.Label(self.QualityIndicators["RefinementResolution"]) + ResolutionBox_frame = gtk.Frame() + self.ResolutionBox = gtk.EventBox() + self.ResolutionBox.add(self.ResolutionValue) + ResolutionBox_frame.add(self.ResolutionBox) + + MolprobityScoreLabel_frame = gtk.Frame() + self.MolprobityScoreLabel = gtk.Label("MolprobityScore") + MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) + self.MolprobityScoreValue = gtk.Label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + MolprobityScoreBox_frame = gtk.Frame() + self.MolprobityScoreBox = gtk.EventBox() + self.MolprobityScoreBox.add(self.MolprobityScoreValue) + MolprobityScoreBox_frame.add(self.MolprobityScoreBox) + + RamachandranOutliersLabel_frame = gtk.Frame() + self.RamachandranOutliersLabel = gtk.Label("Rama Outliers") + RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) + self.RamachandranOutliersValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + RamachandranOutliersBox_frame = gtk.Frame() + self.RamachandranOutliersBox = gtk.EventBox() + self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) + RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) + + RamachandranFavoredLabel_frame = gtk.Frame() + self.RamachandranFavoredLabel = gtk.Label("Rama Favored") + RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) + self.RamachandranFavoredValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + RamachandranFavoredBox_frame = gtk.Frame() + self.RamachandranFavoredBox = gtk.EventBox() + self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) + RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) + + rmsdBondsLabel_frame = gtk.Frame() + self.rmsdBondsLabel = gtk.Label("rmsd(Bonds)") + rmsdBondsLabel_frame.add(self.rmsdBondsLabel) + self.rmsdBondsValue = gtk.Label(self.QualityIndicators["RefinementRmsdBonds"]) + rmsdBondsBox_frame = gtk.Frame() + self.rmsdBondsBox = gtk.EventBox() + self.rmsdBondsBox.add(self.rmsdBondsValue) + rmsdBondsBox_frame.add(self.rmsdBondsBox) + + rmsdAnglesLabel_frame = gtk.Frame() + self.rmsdAnglesLabel = gtk.Label("rmsd(Angles)") + rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) + self.rmsdAnglesValue = gtk.Label(self.QualityIndicators["RefinementRmsdAngles"]) + rmsdAnglesBox_frame = gtk.Frame() + self.rmsdAnglesBox = gtk.EventBox() + self.rmsdAnglesBox.add(self.rmsdAnglesValue) + rmsdAnglesBox_frame.add(self.rmsdAnglesBox) + + MatrixWeightLabel_frame = gtk.Frame() + self.MatrixWeightLabel = gtk.Label("Matrix Weight") + MatrixWeightLabel_frame.add(self.MatrixWeightLabel) + self.MatrixWeightValue = gtk.Label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + MatrixWeightBox_frame = gtk.Frame() + self.MatrixWeightBox = gtk.EventBox() + self.MatrixWeightBox.add(self.MatrixWeightValue) + MatrixWeightBox_frame.add(self.MatrixWeightBox) + + ligandIDLabel_frame = gtk.Frame() + self.ligandIDLabel = gtk.Label("Ligand ID") + ligandIDLabel_frame.add(self.ligandIDLabel) + self.ligandIDValue = gtk.Label(self.spider_plot_data["PANDDA_site_ligand_id"]) + ligandIDBox_frame = gtk.Frame() + self.ligandIDBox = gtk.EventBox() + self.ligandIDBox.add(self.ligandIDValue) + ligandIDBox_frame.add(self.ligandIDBox) + + ligand_occupancyLabel_frame = gtk.Frame() + self.ligand_occupancyLabel = gtk.Label("occupancy") + ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) + self.ligand_occupancyValue = gtk.Label( + self.spider_plot_data["PANDDA_site_occupancy"] + ) + ligand_occupancyBox_frame = gtk.Frame() + self.ligand_occupancyBox = gtk.EventBox() + self.ligand_occupancyBox.add(self.ligand_occupancyValue) + ligand_occupancyBox_frame.add(self.ligand_occupancyBox) + + ligand_BaverageLabel_frame = gtk.Frame() + self.ligand_BaverageLabel = gtk.Label("B average") + ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) + self.ligand_BaverageValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_average"] + ) + ligand_BaverageBox_frame = gtk.Frame() + self.ligand_BaverageBox = gtk.EventBox() + self.ligand_BaverageBox.add(self.ligand_BaverageValue) + ligand_BaverageBox_frame.add(self.ligand_BaverageBox) + + ligand_BratioSurroundingsLabel_frame = gtk.Frame() + self.ligand_BratioSurroundingsLabel = gtk.Label("B ratio") + ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) + self.ligand_BratioSurroundingsValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_ratio_residue_surroundings"] + ) + ligand_BratioSurroundingsBox_frame = gtk.Frame() + self.ligand_BratioSurroundingsBox = gtk.EventBox() + self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) + ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) + + ligand_RSCCLabel_frame = gtk.Frame() + self.ligand_RSCCLabel = gtk.Label("RSCC") + ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) + self.ligand_RSCCValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSCC"]) + ligand_RSCCBox_frame = gtk.Frame() + self.ligand_RSCCBox = gtk.EventBox() + self.ligand_RSCCBox.add(self.ligand_RSCCValue) + ligand_RSCCBox_frame.add(self.ligand_RSCCBox) + + ligand_rmsdLabel_frame = gtk.Frame() + self.ligand_rmsdLabel = gtk.Label("rmsd") + ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) + self.ligand_rmsdValue = gtk.Label(self.spider_plot_data["PANDDA_site_rmsd"]) + ligand_rmsdBox_frame = gtk.Frame() + self.ligand_rmsdBox = gtk.EventBox() + self.ligand_rmsdBox.add(self.ligand_rmsdValue) + ligand_rmsdBox_frame.add(self.ligand_rmsdBox) + + ligand_RSRLabel_frame = gtk.Frame() + self.ligand_RSRLabel = gtk.Label("RSR") + ligand_RSRLabel_frame.add(self.ligand_RSRLabel) + self.ligand_RSRValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSR"]) + ligand_RSRBox_frame = gtk.Frame() + self.ligand_RSRBox = gtk.EventBox() + self.ligand_RSRBox.add(self.ligand_RSRValue) + ligand_RSRBox_frame.add(self.ligand_RSRBox) + + ligand_RSZDLabel_frame = gtk.Frame() + self.ligand_RSZDLabel = gtk.Label("RSZD") + ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) + self.ligand_RSZDValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSZD"]) + ligand_RSZDBox_frame = gtk.Frame() + self.ligand_RSZDBox = gtk.EventBox() + self.ligand_RSZDBox.add(self.ligand_RSZDValue) + ligand_RSZDBox_frame.add(self.ligand_RSZDBox) + + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame() + self.table_left = gtk.Table(8, 2, False) + self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) + self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) + self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) + self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) + self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) + self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) + self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) + self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) + self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) + self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) + self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) + self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) + self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) + self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) + self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) + self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) + frame.add(self.table_left) + hbox.add(frame) + + frame = gtk.Frame() + self.table_right = gtk.Table(8, 2, False) + self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) + self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) + self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) + self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) + self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) + self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) + self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) + self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) + self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) + self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) + self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) + self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) + self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) + self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) + frame.add(self.table_right) + hbox.add(frame) + + outer_frame.add(hbox) + self.vbox.add(outer_frame) + + button = gtk.Button(label="Show MolProbity to-do list") + button.connect("clicked", self.show_molprobity_to_do) + self.vbox.add(button) + self.vbox.pack_start(frame) + + # SPACER + self.vbox.add(gtk.Label(" ")) + + ################################################################################ + # --- hbox for compound picture & spider_plot (formerly: refinement history) --- + frame = gtk.Frame() + self.hbox_for_info_graphics = gtk.HBox() + + # --- compound picture --- + compound_frame = gtk.Frame() + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image = gtk.Image() + self.image.set_from_pixbuf(self.pic) + compound_frame.add(self.image) + self.hbox_for_info_graphics.add(compound_frame) + + # --- Spider Plot --- + spider_plot_frame = gtk.Frame() + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image = gtk.Image() + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + spider_plot_frame.add(self.spider_plot_image) + self.hbox_for_info_graphics.add(spider_plot_frame) + + frame.add(self.hbox_for_info_graphics) + self.vbox.add(frame) + + ################################################################################ + # --- pandda.inspect user comments --- + outer_frame = gtk.Frame(label="pandda.inspect comments") + vbox = gtk.VBox() + ligand_site_name_label_frame = gtk.Frame() + ligand_site_name_label = gtk.Label("Site Name") + ligand_site_name_label_frame.add(ligand_site_name_label) + ligand_inspect_confidence_label_frame = gtk.Frame() + ligand_inspect_confidence_label = gtk.Label("Confidence") + ligand_inspect_confidence_label_frame.add(ligand_inspect_confidence_label) + ligand_inspect_interesting_label_frame = gtk.Frame() + ligand_inspect_interesting_label = gtk.Label("Interesting") + ligand_inspect_interesting_label_frame.add(ligand_inspect_interesting_label) + ligand_inspect_comment_label_frame = gtk.Frame() + ligand_inspect_comment_label = gtk.Label("Comment") + ligand_inspect_comment_label_frame.add(ligand_inspect_comment_label) + ligand_site_name_value_frame = gtk.Frame() + self.ligand_site_name_value = gtk.Label("-") + ligand_site_name_value_frame.add(self.ligand_site_name_value) + ligand_inspect_confidence_value_frame = gtk.Frame() + self.ligand_inspect_confidence_value = gtk.Label("-") + ligand_inspect_confidence_value_frame.add(self.ligand_inspect_confidence_value) + ligand_inspect_interesting_value_frame = gtk.Frame() + self.ligand_inspect_interesting_value = gtk.Label("-") + ligand_inspect_interesting_value_frame.add( + self.ligand_inspect_interesting_value + ) + ligand_inspect_comment_value_frame = gtk.Frame() + self.ligand_inspect_comment_value = gtk.Label("-") + ligand_inspect_comment_value_frame.add(self.ligand_inspect_comment_value) + + frame_pandda_inspect_comments_table = gtk.Frame() + pandda_inspect_comments_table = gtk.Table(2, 6, False) + pandda_inspect_comments_table.attach(ligand_site_name_label_frame, 0, 1, 0, 1) + pandda_inspect_comments_table.attach(ligand_site_name_value_frame, 1, 2, 0, 1) + pandda_inspect_comments_table.attach( + ligand_inspect_confidence_label_frame, 2, 3, 0, 1 + ) + pandda_inspect_comments_table.attach( + ligand_inspect_confidence_value_frame, 3, 4, 0, 1 + ) + pandda_inspect_comments_table.attach( + ligand_inspect_interesting_label_frame, 4, 5, 0, 1 + ) + pandda_inspect_comments_table.attach( + ligand_inspect_interesting_value_frame, 5, 6, 0, 1 + ) + pandda_inspect_comments_table.attach( + ligand_inspect_comment_label_frame, 0, 1, 1, 2 + ) + pandda_inspect_comments_table.attach( + ligand_inspect_comment_value_frame, 1, 6, 1, 2 + ) + + frame_pandda_inspect_comments_table.add(pandda_inspect_comments_table) + vbox.add(frame_pandda_inspect_comments_table) + outer_frame.add(vbox) + self.vbox.pack_start(outer_frame) + + # # SPACER + self.vbox.add(gtk.Label(" ")) + + ################################################################################ + outer_frame = gtk.Frame(label="Sample Navigator") + hboxSample = gtk.HBox() + + # --- crystal navigator combobox --- + frame = gtk.Frame() + self.vbox_sample_navigator = gtk.VBox() + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseXtal) + self.vbox_sample_navigator.add(self.cb) + # --- crystal navigator backward/forward button --- + self.PREVbutton = gtk.Button(label="<<<") + self.NEXTbutton = gtk.Button(label=">>>") + self.PREVbutton.connect("clicked", self.ChangeXtal, -1) + self.NEXTbutton.connect("clicked", self.ChangeXtal, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbutton) + hbox.pack_start(self.NEXTbutton) + self.vbox_sample_navigator.add(hbox) + frame.add(self.vbox_sample_navigator) + hboxSample.add(frame) + + # --- site navigator combobox --- + frame = gtk.Frame() + self.vbox_site_navigator = gtk.VBox() + self.cb_site = gtk.combo_box_new_text() + self.cb_site.connect("changed", self.ChooseSite) + self.vbox_site_navigator.add(self.cb_site) + # --- site navigator backward/forward button --- + self.PREVbuttonSite = gtk.Button(label="<<<") + self.NEXTbuttonSite = gtk.Button(label=">>>") + self.PREVbuttonSite.connect("clicked", self.ChangeSite, -1) + self.NEXTbuttonSite.connect("clicked", self.ChangeSite, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbuttonSite) + hbox.pack_start(self.NEXTbuttonSite) + self.vbox_site_navigator.add(hbox) + frame.add(self.vbox_site_navigator) + hboxSample.add(frame) + + outer_frame.add(hboxSample) + self.vbox.add(outer_frame) + + # SPACER + self.vbox.add(gtk.Label(" ")) + + ################################################################################ + # --- current refinement stage --- + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame(label="Analysis Status") + vbox = gtk.VBox() + self.experiment_stage_button_list = [] + for n, button in enumerate(self.experiment_stage): + if n == 0: + new_button = gtk.RadioButton(None, button[0]) + else: + new_button = gtk.RadioButton(new_button, button[0]) + new_button.connect( + "toggled", self.experiment_stage_button_clicked, button[1] + ) + vbox.add(new_button) + self.experiment_stage_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + # --- ligand confidence --- + frame = gtk.Frame(label="Ligand Confidence") + vbox = gtk.VBox() + self.ligand_confidence_button_list = [] + for n, criteria in enumerate(self.ligand_confidence_category): + if n == 0: + new_button = gtk.RadioButton(None, criteria) + else: + new_button = gtk.RadioButton(new_button, criteria) + new_button.connect( + "toggled", self.ligand_confidence_button_clicked, criteria + ) + vbox.add(new_button) + self.ligand_confidence_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + outer_frame.add(hbox) + self.vbox.pack_start(outer_frame) + + # SPACER + self.vbox.add(gtk.Label(" ")) + + # --- ligand modeling --- + frame = gtk.Frame(label="Ligand Modeling") + self.hbox_for_modeling = gtk.HBox() + self.merge_ligand_button = gtk.Button(label="Merge Ligand") + self.place_ligand_here_button = gtk.Button(label="Place Ligand here") + self.hbox_for_modeling.add(self.place_ligand_here_button) + self.place_ligand_here_button.connect("clicked", self.place_ligand_here) + self.hbox_for_modeling.add(self.merge_ligand_button) + self.merge_ligand_button.connect("clicked", self.merge_ligand_into_protein) + frame.add(self.hbox_for_modeling) + self.vbox.pack_start(frame) + + # --- refinement & options --- + self.hbox_for_refinement = gtk.HBox() + self.REFINEbutton = gtk.Button(label="Refine") + self.RefinementParamsButton = gtk.Button(label="refinement parameters") + self.REFINEbutton.connect("clicked", self.REFINE) + self.hbox_for_refinement.add(self.REFINEbutton) + self.RefinementParamsButton.connect("clicked", self.RefinementParams) + self.hbox_for_refinement.add(self.RefinementParamsButton) + self.vbox.add(self.hbox_for_refinement) + + # --- CANCEL button --- + self.CANCELbutton = gtk.Button(label="CANCEL") + self.CANCELbutton.connect("clicked", self.CANCEL) + self.vbox.add(self.CANCELbutton) + + self.window.add(self.vbox) + self.window.show_all() + + def CANCEL(self, widget): + self.window.destroy() + + def ChangeXtal(self, widget, data=None): + self.index = self.index + data + if self.index < 0: + self.index = 0 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def ChooseXtal(self, widget): + self.xtalID = str(widget.get_active_text()) + for n, item in enumerate(self.Todo): + if str(item[0]) == self.xtalID: + self.index = n + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + + self.ligand_site_name_value.set_label("-") + self.ligand_inspect_confidence_value.set_label("-") + self.ligand_inspect_interesting_value.set_label("-") + self.ligand_inspect_comment_value.set_label("-") + + self.refresh_site_combobox() + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + if str(self.Todo[self.index][0]) is not None: + self.compoundID = str(self.Todo[self.index][1]) + self.refinement_outcome = str(self.Todo[self.index][5]) + self.update_RefinementOutcome_radiobutton() + if ( + self.xtalID not in self.siteDict + ): # i.e. we are not working with a PanDDA model + self.ligand_confidence = str(self.Todo[self.index][6]) + self.update_LigandConfidence_radiobutton() + + self.RefreshData() + + def update_RefinementOutcome_radiobutton(self): + # updating dataset outcome radiobuttons + current_stage = 0 + for i, entry in enumerate(self.experiment_stage): + if entry[1].split()[0] == self.refinement_outcome.split()[0]: + current_stage = i + break + for i, button in enumerate(self.experiment_stage_button_list): + if i == current_stage: + button.set_active(True) + break + + def update_LigandConfidence_radiobutton(self): + # updating ligand confidence radiobuttons + current_stage = 0 + for i, entry in enumerate(self.ligand_confidence_category): + print("--->", entry, self.ligand_confidence) + try: + if entry.split()[0] == self.ligand_confidence.split()[0]: + current_stage = i + break + except IndexError: + pass + for i, button in enumerate(self.ligand_confidence_button_list): + if i == current_stage: + button.set_active(True) + break + + def refresh_site_combobox(self): + # reset self.pandda_index + self.pandda_index = -1 + # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever + # be 100 sites + for n in range(-1, 100): + self.cb_site.remove_text(0) + self.site_index = "0" + self.event_index = "0" + # only repopulate if site exists + if self.xtalID in self.siteDict: + for item in sorted(self.siteDict[self.xtalID]): + self.cb_site.append_text("site: %s - event: %s" % (item[5], item[6])) + + def ChangeSite(self, widget, data=None): + if self.xtalID in self.siteDict: + self.pandda_index = self.pandda_index + data + if self.pandda_index < 0: + self.pandda_index = 0 + if self.pandda_index >= len(self.siteDict[self.xtalID]): + self.pandda_index = 0 + self.cb_site.set_active(self.pandda_index) + + def ChooseSite(self, widget): + tmp = str(widget.get_active_text()) + self.site_index = tmp.split()[1] + self.event_index = tmp.split()[4] + for n, item in enumerate(self.siteDict[self.xtalID]): + if item[5] == self.site_index and item[6] == self.event_index: + self.pandda_index = n + self.RefreshSiteData() + + def RefreshSiteData(self): + if self.pandda_index == -1: + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + else: + self.merge_ligand_button.set_sensitive(False) + self.place_ligand_here_button.set_sensitive(False) + # and remove ligand molecule so that there is no temptation to merge it + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if self.compoundID + ".pdb" in coot.molecule_name(imol): + coot.close_molecule(imol) + + print("pandda index", self.pandda_index) + self.spider_plot = self.siteDict[self.xtalID][self.pandda_index][4] + print("new spider plot:", self.spider_plot) + self.event_map = self.siteDict[self.xtalID][self.pandda_index][0] + print("new event map:", self.event_map) + self.ligand_confidence = str(self.siteDict[self.xtalID][self.pandda_index][7]) + self.update_LigandConfidence_radiobutton() + site_x = float(self.siteDict[self.xtalID][self.pandda_index][1]) + site_y = float(self.siteDict[self.xtalID][self.pandda_index][2]) + site_z = float(self.siteDict[self.xtalID][self.pandda_index][3]) + print("new site coordinates:", site_x, site_y, site_z) + coot.set_rotation_centre(site_x, site_y, site_z) + + self.ligand_site_name_value.set_label( + str(self.siteDict[self.xtalID][self.pandda_index][8]) + ) + self.ligand_inspect_confidence_value.set_label( + str(self.siteDict[self.xtalID][self.pandda_index][9]) + ) + self.ligand_inspect_interesting_value.set_label( + str(self.siteDict[self.xtalID][self.pandda_index][10]) + ) + self.ligand_inspect_comment_value.set_label( + str(self.siteDict[self.xtalID][self.pandda_index][11]) + ) + + self.spider_plot_data = ( + self.db.get_db_pandda_dict_for_sample_and_site_and_event( + self.xtalID, self.site_index, self.event_index + ) + ) + print(">>>>> spider plot data", self.spider_plot_data) + self.ligandIDValue.set_label(self.spider_plot_data["PANDDA_site_ligand_id"]) + try: + self.ligand_occupancyValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_occupancy"]), 2)) + ) + except ValueError: + self.ligand_occupancyValue.set_label("-") + + try: + self.ligand_BaverageValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_B_average"]), 2)) + ) + except ValueError: + self.ligand_BaverageValue.set_label("-") + + try: + self.ligand_BratioSurroundingsValue.set_label( + str( + round( + float( + self.spider_plot_data[ + "PANDDA_site_B_ratio_residue_surroundings" + ] + ), + 2, + ) + ) + ) + except ValueError: + self.ligand_BratioSurroundingsValue.set_label("-") + + try: + self.ligand_RSCCValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSCC"]), 2)) + ) + except ValueError: + self.ligand_RSCCValue.set_label("-") + + try: + self.ligand_rmsdValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_rmsd"]), 2)) + ) + except ValueError: + self.ligand_rmsdValue.set_label("-") + + try: + self.ligand_RSRValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSR"]), 2)) + ) + except ValueError: + self.ligand_RSRValue.set_label("-") + + try: + self.ligand_RSZDValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSZD"]), 2)) + ) + except ValueError: + self.ligand_RSZDValue.set_label("-") + + ################################################################################ + # delete old Event MAPs + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if "map.native.ccp4" in coot.molecule_name(imol): + coot.close_molecule(imol) + + ################################################################################ + # Spider plot + # Note: refinement history was shown instead previously + if os.path.isfile(self.spider_plot): + spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) + else: + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + ################################################################################ + # check for PANDDAs EVENT maps + if os.path.isfile(self.event_map): + coot.handle_read_ccp4_map((self.event_map), 0) + for imol in coot_utils_XChem.molecule_number_list(): + if self.event_map in coot.molecule_name(imol): + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + + def experiment_stage_button_clicked(self, widget, data=None): + self.db_dict_mainTable["RefinementOutcome"] = data + print( + "==> XCE: setting Refinement Outcome for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.update_data_source(self.xtalID, self.db_dict_mainTable) + + def ligand_confidence_button_clicked(self, widget, data=None): + print("PANDDA_index", self.pandda_index) + if self.pandda_index == -1: + self.db_dict_mainTable["RefinementLigandConfidence"] = data + print( + "==> XCE: setting Ligand Confidence for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.update_data_source(self.xtalID, self.db_dict_mainTable) + self.Todo[self.index][6] = data + else: + self.db_dict_panddaTable["PANDDA_site_confidence"] = data + print( + "==> XCE: setting Ligand Confidence for " + + self.xtalID + + " (site=" + + str(self.site_index) + + ", event=" + + str(self.event_index) + + ") to " + + str(data) + + " in panddaTable of datasource" + ) + self.db.update_site_event_panddaTable( + self.xtalID, self.site_index, self.event_index, self.db_dict_panddaTable + ) + self.siteDict[self.xtalID][self.pandda_index][7] = data + + def RefreshData(self): + # reset spider plot image + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + # initialize Refinement library + self.Refine = XChemRefine.RefineOld( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ) + self.Serial = self.Refine.GetSerial() + if self.Serial == 1: + # i.e. no refinement has been done; data is probably straight out of dimple + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, self.pdb_style), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + + # all this information is now updated in the datasource after each refinement + # cycle + self.QualityIndicators = self.db.get_db_dict_for_sample(self.xtalID) + + ################################################################################ + # history + # if the structure was previously refined, try to read the parameters + if self.Serial > 1: + self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) + + ################################################################################ + # update pdb & maps + + ################################################################################ + # delete old PDB and MAP files + # - get a list of all molecules which are currently opened in COOT + # - remove all molecules/ maps before loading a new set + if len(coot_utils_XChem.molecule_number_list()) > 0: + for item in coot_utils_XChem.molecule_number_list(): + coot.close_molecule(item) + + ################################################################################ + # read new PDB files + # read protein molecule after ligand so that this one is the active molecule + coot.set_nomenclature_errors_on_read("ignore") + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.compoundID + ".pdb") + ): + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ), + 0, + ) + self.mol_dict["ligand"] = imol + coot.read_cif_dictionary( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ) + if not os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, self.pdb_style), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "dimple.pdb"), 0 + ) + else: + self.go_to_next_xtal() + self.mol_dict["protein"] = imol + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith(self.pdb_style): + # master switch to show symmetry molecules + coot.set_show_symmetry_master(1) + coot.set_show_symmetry_molecule(item, 1) # show symm for model + + ################################################################################ + # read fofo maps + # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map + # read 2fofc map last so that one can change its contour level + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "2fofc.map") + ): + coot.set_default_initial_contour_level_for_difference_map(3) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "fofc.map"), 1 + ) + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "2fofc.map"), 0 + ) + coot.set_last_map_colour(0, 0, 1) + else: + # try to open mtz file with same name as pdb file + coot.set_default_initial_contour_level_for_map(1) + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "dimple.mtz") + ) + + ################################################################################ + # update Quality Indicator table + try: + self.RRfreeValue.set_label( + str(round(float(self.QualityIndicators["RefinementRcryst"]), 3)) + + " / " + + str(round(float(self.QualityIndicators["RefinementRfree"]), 3)) + ) + except ValueError: + self.RRfreeValue.set_label("-") + + try: + self.RRfreeBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRfreeTraficLight"] + ), + ) + except ValueError: + pass + self.ResolutionValue.set_label(self.QualityIndicators["RefinementResolution"]) + try: + self.ResolutionBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementResolutionTL"]), + ) + except ValueError: + pass + self.MolprobityScoreValue.set_label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + try: + self.MolprobityScoreBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementMolProbityScoreTL"] + ), + ) + except ValueError: + pass + self.RamachandranOutliersValue.set_label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + try: + self.RamachandranOutliersBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranOutliersTL"] + ), + ) + except ValueError: + pass + self.RamachandranFavoredValue.set_label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + try: + self.RamachandranFavoredBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranFavoredTL"] + ), + ) + except ValueError: + pass + self.rmsdBondsValue.set_label(self.QualityIndicators["RefinementRmsdBonds"]) + try: + self.rmsdBondsBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdBondsTL"]), + ) + except ValueError: + pass + self.rmsdAnglesValue.set_label(self.QualityIndicators["RefinementRmsdAngles"]) + try: + self.rmsdAnglesBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdAnglesTL"]), + ) + except ValueError: + pass + self.MatrixWeightValue.set_label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + + try: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".png" + ) + ) + except gobject.GError: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image.set_from_pixbuf(self.pic) + + def go_to_next_xtal(self): + self.index += 1 + if self.index >= len(self.Todo): + self.index = len(self.Todo) + self.cb.set_active(self.index) + + def REFINE(self, widget): + ####################################################### + # create folder for new refinement cycle + os.mkdir( + os.path.join( + self.project_directory, self.xtalID, "Refine_" + str(self.Serial) + ) + ) + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ folder + # note: the user has to make sure that the ligand file was merged into main file + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith(self.pdb_style): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + elif coot.molecule_name(item).endswith("dimple.pdb"): + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + + ####################################################### + # run REFMAC + self.Refine.RunRefmac( + self.Serial, self.RefmacParams, self.external_software, self.xce_logfile + ) + + self.index += 1 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def RefinementParams(self, widget): + print("\n==> XCE: changing refinement parameters") + self.RefmacParams = self.Refine.RefinementParams(self.RefmacParams) + + def set_selection_mode(self, widget): + self.selection_mode = widget.get_active_text() + + def get_samples_to_look_at(self, widget): + if self.selection_mode == "": + self.status_label.set_text("select model stage") + return + self.status_label.set_text("checking datasource for samples... ") + # first remove old samples if present + if len(self.Todo) != 0: + for n, item in enumerate(self.Todo): + self.cb.remove_text(0) + self.Todo = [] + self.siteDict = {} + self.Todo, self.siteDict = self.db.get_todoList_for_coot(self.selection_mode) + self.status_label.set_text("found %s samples" % len(self.Todo)) + # refresh sample CB + for item in sorted(self.Todo): + self.cb.append_text("%s" % item[0]) + if self.siteDict == {}: + self.cb_site.set_sensitive(False) + self.PREVbuttonSite.set_sensitive(False) + self.NEXTbuttonSite.set_sensitive(False) + else: + self.cb_site.set_sensitive(True) + self.PREVbuttonSite.set_sensitive(True) + self.NEXTbuttonSite.set_sensitive(True) + + def update_plot(self, refinement_cycle, Rfree, Rcryst): + fig = Figure(figsize=(2, 2), dpi=50) + Plot = fig.add_subplot(111) + Plot.set_ylim([0, max(Rcryst + Rfree)]) + Plot.set_xlabel("Refinement Cycle", fontsize=12) + Plot.plot(refinement_cycle, Rfree, label="Rfree", linewidth=2) + Plot.plot(refinement_cycle, Rcryst, label="Rcryst", linewidth=2) + Plot.legend( + bbox_to_anchor=(0.0, 1.02, 1.0, 0.102), + loc=3, + ncol=2, + mode="expand", + borderaxespad=0.0, + fontsize=12, + ) + return fig + + def place_ligand_here(self, widget): + print("===> XCE: moving ligand to pointer") + print("LIGAND: ", self.mol_dict["ligand"]) + coot_utils_XChem.move_molecule_here(self.mol_dict["ligand"]) + + def merge_ligand_into_protein(self, widget): + print("===> XCE: merge ligand into protein structure") + coot.merge_molecules_py([self.mol_dict["ligand"]], self.mol_dict["protein"]) + print("===> XCE: deleting ligand molecule") + coot.close_molecule(self.mol_dict["ligand"]) + + def show_molprobity_to_do(self, widget): + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + else: + print( + "==> XCE: cannot find " + + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import coot_utils_XChem + from xce.lib import XChemDB + from xce.lib import XChemRefine + from xce.lib import XChemUtils + + GUI().StartGUI() diff --git a/coot/XChemCootReference.py b/coot/XChemCootReference.py new file mode 100755 index 00000000..ebc9b14f --- /dev/null +++ b/coot/XChemCootReference.py @@ -0,0 +1,710 @@ +import sys +import glob +import os +import pickle +import time + +import coot +import gtk +from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas +from matplotlib.figure import Figure + +# had to adapt the original coot_utils.py file +# otherwise unable to import the original file without complaints about missing modules +# etc. +# modified file is now in $XChemExplorer_DIR/lib + + +class GUI(object): + """ + main class which opens the actual GUI + """ + + def __init__(self): + ################################################################################ + # read in settings file from XChemExplorer to set the relevant paths + self.settings = pickle.load(open(".xce_settings.pkl", "rb")) + self.database_directory = self.settings["database_directory"] + self.xce_logfile = self.settings["xce_logfile"] + self.Logfile = XChemLog.updateLog(self.xce_logfile) + self.Logfile.insert("starting COOT gui for reference model refinement") + self.data_source = self.settings["data_source"] + + # checking for external software packages + self.external_software = XChemUtils.external_software(self.xce_logfile).check() + + # the Folder is kind of a legacy thing because my inital idea was to have + # separate folders for Data Processing and Refinement + self.reference_directory = self.settings["reference_directory"] + self.refinementDir = "" + self.Serial = 0 + self.Refine = None + + self.xtalID = "" + self.compoundID = "" + self.spider_plot = "" + self.pdbFile = "" + self.mtzFree = "" + + self.pdb_style = "refine.pdb" + self.mtz_style = "refine.mtz" + + # stores imol of currently loaded molecules and maps + self.mol_dict = { + "protein": -1, + "ligand": -1, + "2fofc": -1, + "fofc": -1, + "event": -1, + } + + self.job_running = False + + ################################################################################ + # some COOT settings + coot.set_map_radius(17) + coot.set_colour_map_rotation_for_map(0) + + self.QualityIndicators = { + "Rcryst": "-", + "Rfree": "-", + "RfreeTL": "gray", + "ResolutionHigh": "-", + "ResolutionColor": "gray", + "MolprobityScore": "-", + "MolprobityScoreColor": "gray", + "RamachandranOutliers": "-", + "RamachandranOutliersColor": "gray", + "RamachandranFavored": "-", + "RamachandranFavoredColor": "gray", + "rmsdBonds": "-", + "rmsdBondsTL": "gray", + "rmsdAngles": "-", + "rmsdAnglesTL": "gray", + "MatrixWeight": "-", + } + + # default refmac parameters + self.RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + } + + def StartGUI(self): + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_default_size(400, 800) + self.window.set_title("Reference Model Builder") + self.vbox = gtk.VBox() # this is the main container + + ################################################################################ + # --- PDB file selection --- + # checking for pdb files in reference directory + referenceFiles = [] + for files in glob.glob( + os.path.join(self.reference_directory, "*-ground-state.pdb") + ): + pdbFile = files[files.rfind("/") + 1 :] + referenceFiles.append(pdbFile) + frame = gtk.Frame(label="Select PDB file") + hbox = gtk.HBox() + self.cb_select_pdb = gtk.combo_box_new_text() + for pdbFile in referenceFiles: + self.cb_select_pdb.append_text(pdbFile) + hbox.add(self.cb_select_pdb) + frame.add(hbox) + self.vbox.pack_start(frame) + + self.load_pdb_file_button = gtk.Button(label="Load") + self.load_pdb_file_button.connect("clicked", self.load_pdb_file) + hbox.add(self.load_pdb_file_button) + frame.add(hbox) + self.vbox.pack_start(frame) + + # SPACER + self.vbox.add(gtk.Label(" ")) + + frame = gtk.Frame(label="MTZ file to refine against") + hbox = gtk.HBox() + self.mtzFree = "" + self.mtzFree_label = gtk.Label() + hbox.add(self.mtzFree_label) + frame.add(hbox) + self.vbox.pack_start(frame) + + # SPACER + self.vbox.add(gtk.Label(" ")) + + frame = gtk.Frame(label="MTZ file after refinement") + hbox = gtk.HBox() + self.mtzRefine_label = gtk.Label() + hbox.add(self.mtzRefine_label) + frame.add(hbox) + self.vbox.pack_start(frame) + + # SPACER + self.vbox.add(gtk.Label(" \n ")) + + ################################################################################ + # --- Refinement History --- + frame = gtk.Frame(label="Refinement History") + self.hbox_for_info_graphics = gtk.HBox() + self.canvas = FigureCanvas(self.update_plot([0], [0], [0])) + self.canvas.set_size_request(190, 190) + self.hbox_for_info_graphics.add(self.canvas) + frame.add(self.hbox_for_info_graphics) + self.vbox.pack_start(frame) + + ################################################################################ + # --- status window --- + frame = gtk.Frame(label="Status") + vbox = gtk.VBox() + self.spinnerBox = gtk.VBox() + vbox.add(self.spinnerBox) + self.status_label = gtk.Label() + vbox.add(self.status_label) + frame.add(vbox) + self.status_label.set_text("idle") + + self.vbox.pack_start(frame) + + ################################################################################ + # --- Refinement Statistics --- + # next comes a section which displays some global quality indicators + # a combination of labels and textview widgets, arranged in a table + + RRfreeLabel_frame = gtk.Frame() + self.RRfreeLabel = gtk.Label("R/Rfree") + RRfreeLabel_frame.add(self.RRfreeLabel) + self.RRfreeValue = gtk.Label( + self.QualityIndicators["Rcryst"] + "/" + self.QualityIndicators["Rfree"] + ) + RRfreeBox_frame = gtk.Frame() + self.RRfreeBox = gtk.EventBox() + self.RRfreeBox.add(self.RRfreeValue) + RRfreeBox_frame.add(self.RRfreeBox) + + ResolutionLabel_frame = gtk.Frame() + self.ResolutionLabel = gtk.Label("Resolution") + ResolutionLabel_frame.add(self.ResolutionLabel) + self.ResolutionValue = gtk.Label(self.QualityIndicators["ResolutionHigh"]) + ResolutionBox_frame = gtk.Frame() + self.ResolutionBox = gtk.EventBox() + self.ResolutionBox.add(self.ResolutionValue) + ResolutionBox_frame.add(self.ResolutionBox) + + MolprobityScoreLabel_frame = gtk.Frame() + self.MolprobityScoreLabel = gtk.Label("MolprobityScore") + MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) + self.MolprobityScoreValue = gtk.Label(self.QualityIndicators["MolprobityScore"]) + MolprobityScoreBox_frame = gtk.Frame() + self.MolprobityScoreBox = gtk.EventBox() + self.MolprobityScoreBox.add(self.MolprobityScoreValue) + MolprobityScoreBox_frame.add(self.MolprobityScoreBox) + + RamachandranOutliersLabel_frame = gtk.Frame() + self.RamachandranOutliersLabel = gtk.Label("Rama Outliers") + RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) + self.RamachandranOutliersValue = gtk.Label( + self.QualityIndicators["RamachandranOutliers"] + ) + RamachandranOutliersBox_frame = gtk.Frame() + self.RamachandranOutliersBox = gtk.EventBox() + self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) + RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) + + RamachandranFavoredLabel_frame = gtk.Frame() + self.RamachandranFavoredLabel = gtk.Label("Rama Favored") + RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) + self.RamachandranFavoredValue = gtk.Label( + self.QualityIndicators["RamachandranFavoredColor"] + ) + RamachandranFavoredBox_frame = gtk.Frame() + self.RamachandranFavoredBox = gtk.EventBox() + self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) + RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) + + rmsdBondsLabel_frame = gtk.Frame() + self.rmsdBondsLabel = gtk.Label("rmsd(Bonds)") + rmsdBondsLabel_frame.add(self.rmsdBondsLabel) + self.rmsdBondsValue = gtk.Label(self.QualityIndicators["rmsdBonds"]) + rmsdBondsBox_frame = gtk.Frame() + self.rmsdBondsBox = gtk.EventBox() + self.rmsdBondsBox.add(self.rmsdBondsValue) + rmsdBondsBox_frame.add(self.rmsdBondsBox) + + rmsdAnglesLabel_frame = gtk.Frame() + self.rmsdAnglesLabel = gtk.Label("rmsd(Angles)") + rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) + self.rmsdAnglesValue = gtk.Label(self.QualityIndicators["rmsdAngles"]) + rmsdAnglesBox_frame = gtk.Frame() + self.rmsdAnglesBox = gtk.EventBox() + self.rmsdAnglesBox.add(self.rmsdAnglesValue) + rmsdAnglesBox_frame.add(self.rmsdAnglesBox) + + MatrixWeightLabel_frame = gtk.Frame() + self.MatrixWeightLabel = gtk.Label("Matrix Weight") + MatrixWeightLabel_frame.add(self.MatrixWeightLabel) + self.MatrixWeightValue = gtk.Label(self.QualityIndicators["MatrixWeight"]) + MatrixWeightBox_frame = gtk.Frame() + self.MatrixWeightBox = gtk.EventBox() + self.MatrixWeightBox.add(self.MatrixWeightValue) + MatrixWeightBox_frame.add(self.MatrixWeightBox) + + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame() + self.table_left = gtk.Table(8, 2, False) + self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) + self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) + self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) + self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) + self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) + self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) + self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) + self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) + self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) + self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) + self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) + self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) + self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) + self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) + self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) + self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) + frame.add(self.table_left) + hbox.add(frame) + + outer_frame.add(hbox) + self.vbox.add(outer_frame) + + button = gtk.Button(label="Show MolProbity to-do list") + button.connect("clicked", self.show_molprobity_to_do) + self.vbox.add(button) + self.vbox.pack_start(frame) + + # SPACER + self.vbox.add(gtk.Label(" ")) + + # --- refinement & options --- + self.hbox_for_refinement = gtk.HBox() + self.REFINEbutton = gtk.Button(label="Refine") + self.RefinementParamsButton = gtk.Button(label="refinement parameters") + self.REFINEbutton.connect("clicked", self.REFINE) + self.hbox_for_refinement.add(self.REFINEbutton) + self.RefinementParamsButton.connect("clicked", self.RefinementParams) + self.hbox_for_refinement.add(self.RefinementParamsButton) + self.vbox.add(self.hbox_for_refinement) + + # --- CANCEL button --- + self.CANCELbutton = gtk.Button(label="CANCEL") + self.CANCELbutton.connect("clicked", self.CANCEL) + self.vbox.add(self.CANCELbutton) + + self.window.add(self.vbox) + self.window.show_all() + + def CANCEL(self, widget): + self.window.destroy() + + def RefreshData(self): + # initialize Refinement library + self.Refine = XChemRefine.Refine( + self.reference_directory, + self.refinementDir, + "dummy_compound_ID", + "dummy_database", + ) + self.Serial = self.Refine.GetSerial() + print("====> Serial", self.Serial) + + ################################################################################ + # history + # if the structure was previously refined, try to read the parameters + self.hbox_for_info_graphics.remove(self.canvas) + if self.Serial > 1: + self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) + refinement_cycle, Rfree, Rcryst = self.Refine.GetRefinementHistory() + self.canvas = FigureCanvas( + self.update_plot(refinement_cycle, Rfree, Rcryst) + ) + else: + self.canvas = FigureCanvas( + self.update_plot([0], [0], [0]) + ) # a gtk.DrawingArea + self.canvas.set_size_request(190, 190) + self.hbox_for_info_graphics.add(self.canvas) + self.canvas.show() + + ################################################################################ + # update Quality Indicator table + print(self.QualityIndicators) + try: + self.RRfreeValue.set_label( + str(round(float(self.QualityIndicators["Rcryst"]), 3)) + + " / " + + str(round(float(self.QualityIndicators["Rfree"]), 3)) + ) + except ValueError: + self.RRfreeValue.set_label("-") + + try: + self.RRfreeBox.modify_bg( + gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators["RfreeTL"]) + ) + except ValueError: + pass + self.ResolutionValue.set_label(self.QualityIndicators["ResolutionHigh"]) + try: + self.ResolutionBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["ResolutionColor"]), + ) + except ValueError: + pass + self.MolprobityScoreValue.set_label(self.QualityIndicators["MolprobityScore"]) + try: + self.MolprobityScoreBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["MolprobityScoreColor"]), + ) + except ValueError: + pass + self.RamachandranOutliersValue.set_label( + self.QualityIndicators["RamachandranOutliers"] + ) + try: + self.RamachandranOutliersBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RamachandranOutliersColor"] + ), + ) + except ValueError: + pass + self.RamachandranFavoredValue.set_label( + self.QualityIndicators["RamachandranFavored"] + ) + try: + self.RamachandranFavoredBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RamachandranFavoredColor"]), + ) + except ValueError: + pass + self.rmsdBondsValue.set_label(self.QualityIndicators["rmsdBonds"]) + try: + self.rmsdBondsBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["rmsdBondsTL"]), + ) + except ValueError: + pass + self.rmsdAnglesValue.set_label(self.QualityIndicators["rmsdAngles"]) + try: + self.rmsdAnglesBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["rmsdAnglesTL"]), + ) + except ValueError: + pass + self.MatrixWeightValue.set_label(self.QualityIndicators["MatrixWeight"]) + + def REFINE(self, widget): + if self.job_running: + coot.info_dialog("*** refinement in progress ***") + return None + + ####################################################### + # create folder for new refinement cycle and check if free.mtz exists + if not os.path.isdir( + os.path.join(self.reference_directory, self.refinementDir) + ): + os.mkdir(os.path.join(self.reference_directory, self.refinementDir)) + if not os.path.isdir( + os.path.join( + self.reference_directory, + self.refinementDir, + "Refine_" + str(self.Serial), + ) + ): + os.mkdir( + os.path.join( + self.reference_directory, + self.refinementDir, + "Refine_" + str(self.Serial), + ) + ) + if not os.path.isfile( + os.path.join( + self.reference_directory, + self.refinementDir, + self.refinementDir + ".free.mtz", + ) + ): + os.chdir(os.path.join(self.reference_directory, self.refinementDir)) + os.symlink(self.mtzFree, self.refinementDir + ".free.mtz") + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ folder + # note: the user has to make sure that the ligand file was merged into main file + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item) in self.pdbFile: + coot.write_pdb_file( + item, + os.path.join( + self.reference_directory, + self.refinementDir, + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + break + + self.Refine.RunRefmac( + self.Serial, + self.RefmacParams, + self.external_software, + self.xce_logfile, + None, + get_token(fetch_password_gtk), + ) + self.status_label.set_text("Refinement running...") + + # waiting 1s to make sure that REFINEMENT_IN_PROGRESS is written + time.sleep(1) + snooze = 0 + while os.path.exists( + os.path.join( + self.reference_directory, self.refinementDir, "REFINEMENT_IN_PROGRESS" + ) + ): + time.sleep(10) + print( + "==> XCE: waiting for refinement to finish; elapsed time = " + + str(snooze) + + "s" + ) + snooze += 10 + self.update_pdb_mtz_files("") + + def RefinementParams(self, widget): + print("\n==> XCE: changing refinement parameters") + self.RefmacParams = self.Refine.RefinementParams(self.RefmacParams) + + def set_selection_mode(self, widget): + self.selection_mode = widget.get_active_text() + + def load_pdb_file(self, widget): + pdbRoot = self.cb_select_pdb.get_active_text() + if self.pdbFile != "": + self.Logfile.error( + "sorry, you need to close the current instance of COOT and start again" + ) + return None + + self.refinementDir = pdbRoot.replace(".pdb", "") + self.update_pdb_mtz_files(pdbRoot) + + def update_pdb_mtz_files(self, pdbRoot): + # first remove all pdb and mtz files from memory + self.Logfile.insert("removing all PDB and MTZ files from memory") + if len(coot_utils_XChem.molecule_number_list()) > 0: + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith( + ".pdb" + ) or ".mtz" in coot.molecule_name(item): + self.Logfile.insert("removing %s" % coot.molecule_name(item)) + coot.close_molecule(item) + + coot.set_nomenclature_errors_on_read("ignore") + # first we check if there is a refinement folder and the respective refine.pdb + # from previous refinement cycles + Root = self.cb_select_pdb.get_active_text() + print("ROOT", Root) + print( + "REFI_DIR", + os.path.join(self.reference_directory, self.refinementDir, "refine.pdb"), + ) + if os.path.isfile( + os.path.join(self.reference_directory, self.refinementDir, "refine.pdb") + ): + os.chdir(self.reference_directory) + print("CURRENT DIR", os.getcwd()) + os.system("/bin/rm %s 2> /dev/null" % Root) + os.symlink( + os.path.realpath(os.path.join(self.refinementDir, "refine.pdb")), + "%s" % Root, + ) + self.pdbFile = os.path.join( + self.reference_directory, self.refinementDir, "refine.pdb" + ) + elif os.path.isfile(os.path.join(self.reference_directory, Root)): + self.pdbFile = os.path.join(self.reference_directory, Root) + else: + self.Logfile.error("cannot find PDB file") + + if self.pdbFile != "": + coot.set_colour_map_rotation_on_read_pdb(0) + imol = coot.handle_read_draw_molecule_with_recentre(self.pdbFile, 0) + self.QualityIndicators = XChemUtils.parse().PDBheader( + os.path.join(self.pdbFile) + ) + self.QualityIndicators.update( + XChemUtils.logtools( + os.path.join( + self.reference_directory, + self.refinementDir, + "refine_molprobity.log", + ) + ).phenix_molprobity() + ) + self.QualityIndicators.update( + XChemUtils.logtools( + os.path.join( + self.reference_directory, + self.refinementDir, + "Refine_" + str(self.Serial), + "refmac.log", + ) + ).refmac_log() + ) + self.mol_dict["protein"] = imol + + if self.mtzFree == "": + print( + "FREE", + os.path.join( + self.reference_directory, pdbRoot.replace(".pdb", "") + ".free.mtz" + ), + ) + if os.path.isfile( + os.path.join( + self.reference_directory, pdbRoot.replace(".pdb", "") + ".free.mtz" + ) + ): + self.mtzFree = os.path.join( + self.reference_directory, pdbRoot.replace(".pdb", "") + ".free.mtz" + ) + self.mtzFree_label.set_text(pdbRoot.replace(".pdb", "") + ".free.mtz") + self.REFINEbutton.set_sensitive(True) + else: + self.mtzFree_label.set_text("missing file") + self.Logfile.error( + "cannot find file with F,SIGF and FreeR_flag;" + " cannot start refinement" + ) + self.REFINEbutton.set_sensitive(False) + + if os.path.isfile( + os.path.join(self.reference_directory, self.refinementDir, "refine.mtz") + ): + mtzRefineReal = os.path.realpath( + os.path.join(self.reference_directory, self.refinementDir, "refine.mtz") + ) + mtzRefineCurrent = mtzRefineReal.replace( + os.path.join(self.reference_directory, self.refinementDir + "/"), "" + ) + self.mtzRefine_label.set_text(mtzRefineCurrent) + coot.set_default_initial_contour_level_for_map(1) + if os.path.isfile( + os.path.join( + self.reference_directory, self.refinementDir, self.mtz_style + ) + ): + coot.auto_read_make_and_draw_maps( + os.path.join( + self.reference_directory, self.refinementDir, self.mtz_style + ) + ) + else: + self.mtzRefine_label.set_text("missing file") + self.Logfile.warning( + "cannot find file with F,SIGF and FreeR_flag; cannot start refinement" + ) + + groundStateMap = os.path.join( + self.reference_directory, Root + "-mean-map.native.ccp4" + ).replace(".pdb", "") + print("===>", groundStateMap) + if os.path.isfile(groundStateMap): + imol = coot.handle_read_ccp4_map(groundStateMap, 0) + coot.set_contour_level_in_sigma(imol, 1) + coot.set_last_map_colour(0.6, 0.6, 0) + else: + print("==> XCE: ERROR - cannot find ground state mean map!") + + self.RefreshData() + + def show_molprobity_to_do(self, widget): + if os.path.isfile( + os.path.join( + self.reference_directory, + self.refinementDir, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ): + coot.run_script( + os.path.join( + self.reference_directory, + self.refinementDir, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + else: + print( + "==> XCE: cannot find " + + os.path.join( + self.reference_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + + def update_plot(self, refinement_cycle, Rfree, Rcryst): + fig = Figure(figsize=(2, 2), dpi=50) + Plot = fig.add_subplot(111) + Plot.set_ylim([0, max(Rcryst + Rfree)]) + Plot.set_xlabel("Refinement Cycle", fontsize=12) + Plot.plot(refinement_cycle, Rfree, label="Rfree", linewidth=2) + Plot.plot(refinement_cycle, Rcryst, label="Rcryst", linewidth=2) + Plot.legend( + bbox_to_anchor=(0.0, 1.02, 1.0, 0.102), + loc=3, + ncol=2, + mode="expand", + borderaxespad=0.0, + fontsize=12, + ) + return fig + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import coot_utils_XChem + from xce.lib import XChemLog + from xce.lib import XChemRefine + from xce.lib import XChemUtils + from xce.lib.cluster.slurm import get_token, fetch_password_gtk + + GUI().StartGUI() diff --git a/coot/XChemCootTwin.py b/coot/XChemCootTwin.py new file mode 100755 index 00000000..a3c37f84 --- /dev/null +++ b/coot/XChemCootTwin.py @@ -0,0 +1,1698 @@ +import sys +import glob +import os +import pickle + +import coot +import gobject +import gtk +from matplotlib.figure import Figure + +# had to adapt the original coot_utils.py file +# otherwise unable to import the original file without complaints about missing modules +# modified file is now in $XChemExplorer_DIR/lib + + +class GUI(object): + """ + main class which opens the actual GUI + """ + + def __init__(self): + ################################################################################ + # read in settings file from XChemExplorer to set the relevant paths + self.settings = pickle.load(open(".xce_settings.pkl", "rb")) + + self.database_directory = self.settings["database_directory"] + self.xce_logfile = self.settings["xce_logfile"] + self.Logfile = XChemLog.updateLog(self.xce_logfile) + self.Logfile.insert("==> COOT: starting coot plugin...") + self.data_source = self.settings["data_source"] + self.db = XChemDB.data_source(self.data_source) + + print(self.settings) + + # checking for external software packages + self.external_software = XChemUtils.external_software(self.xce_logfile).check() + + self.selection_criteria = [ + "0 - All Datasets", + "1 - Analysis Pending", + "2 - PANDDA model", + "3 - In Refinement", + "4 - CompChem ready", + "5 - Deposition ready", + "6 - Deposited", + "7 - Analysed & Rejected", + ] + + self.experiment_stage = [ + ["Review PANDDA export", "2 - PANDDA model", 65000, 0, 0], + ["In Refinement", "3 - In Refinement", 65000, 0, 0], + ["Comp Chem Ready!", "4 - CompChem ready", 65000, 0, 0], + ["Ready for Deposition!", "5 - Deposition ready", 65000, 0, 0], + ["In PDB", "6 - Deposited", 65000, 0, 0], + ["Analysed & Rejected", "7 - Analysed & Rejected", 65000, 0, 0], + ] + + self.ligand_confidence_category = [ + "0 - no ligand present", + "1 - Low Confidence", + "2 - Correct ligand, weak density", + "3 - Clear density, unexpected ligand", + "4 - High Confidence", + ] + + # this decides which samples will be looked at + self.selection_mode = "" + self.pandda_index = -1 # refers to the number of sites + self.site_index = "0" + self.event_index = "0" + + # the Folder is kind of a legacy thing because my inital idea was to have + # separate folders for Data Processing and Refinement + self.project_directory = self.settings["initial_model_directory"] + self.Serial = 0 + self.panddaSerial = 0 + self.Refine = None + self.index = -1 + self.Todo = [] + self.siteDict = {} + + self.xtalID = "" + self.compoundID = "" + self.ground_state_mean_map = "" + self.spider_plot = "" + self.ligand_confidence = "" + + self.pdb_style = "refine.pdb" + self.mtz_style = "refine.mtz" + + self.covLinkObject = coot.new_generic_object_number("covalent bond") + self.covLinkAtomSpec = None + + self.label = None + + # stores imol of currently loaded molecules and maps + self.mol_dict = { + "protein": -1, + "ligand": -1, + "2fofc": -1, + "fofc": -1, + "event": -1, + "ligand_stereo": [], + } + + # two dictionaries which are flushed when a new crystal is loaded + # and which contain information to update the data source if necessary + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + + self.label_button_list = [] + + ################################################################################ + # some COOT settings + coot.set_map_radius(17) + coot.set_colour_map_rotation_for_map(0) + # coot.set_colour_map_rotation_on_read_pdb_flag(21) + + self.QualityIndicators = { + "RefinementRcryst": "-", + "RefinementRfree": "-", + "RefinementRfreeTraficLight": "gray", + "RefinementResolution": "-", + "RefinementResolutionTL": "gray", + "RefinementMolProbityScore": "-", + "RefinementMolProbityScoreTL": "gray", + "RefinementRamachandranOutliers": "-", + "RefinementRamachandranOutliersTL": "gray", + "RefinementRamachandranFavored": "-", + "RefinementRamachandranFavoredTL": "gray", + "RefinementRmsdBonds": "-", + "RefinementRmsdBondsTL": "gray", + "RefinementRmsdAngles": "-", + "RefinementRmsdAnglesTL": "gray", + "RefinementMatrixWeight": "-", + } + + self.spider_plot_data = { + "PANDDA_site_ligand_id": "-", + "PANDDA_site_occupancy": "-", + "PANDDA_site_B_average": "-", + "PANDDA_site_B_ratio_residue_surroundings": "-", + "PANDDA_site_RSCC": "-", + "PANDDA_site_rmsd": "-", + "PANDDA_site_RSR": "-", + "PANDDA_site_RSZD": "-", + } + + # default refmac parameters + self.RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + } + + def StartGUI(self): + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_default_size(400, 800) + self.window.set_title("XChemExplorer") + self.vbox = gtk.VBox() # this is the main container + + ################################################################################ + # --- Sample Selection --- + + frame = gtk.Frame(label="Select Samples") + self.hbox_select_samples = gtk.HBox() + + self.cb_select_samples = gtk.combo_box_new_text() + self.cb_select_samples.connect("changed", self.set_selection_mode) + for citeria in self.selection_criteria: + self.cb_select_samples.append_text(citeria) + self.hbox_select_samples.add(self.cb_select_samples) + + self.select_samples_button = gtk.Button(label="GO") + self.select_samples_button.connect("clicked", self.get_samples_to_look_at) + self.hbox_select_samples.add(self.select_samples_button) + frame.add(self.hbox_select_samples) + self.vbox.pack_start(frame) + + ################################################################################ + # --- status window --- + frame = gtk.Frame() + self.status_label = gtk.Label() + frame.add(self.status_label) + self.vbox.pack_start(frame) + + ################################################################################ + # --- Refinement Statistics --- + # next comes a section which displays some global quality indicators + # a combination of labels and textview widgets, arranged in a table + + RRfreeLabel_frame = gtk.Frame() + self.RRfreeLabel = gtk.Label("R/Rfree") + RRfreeLabel_frame.add(self.RRfreeLabel) + self.RRfreeValue = gtk.Label( + self.QualityIndicators["RefinementRcryst"] + + "/" + + self.QualityIndicators["RefinementRfree"] + ) + RRfreeBox_frame = gtk.Frame() + self.RRfreeBox = gtk.EventBox() + self.RRfreeBox.add(self.RRfreeValue) + RRfreeBox_frame.add(self.RRfreeBox) + + ResolutionLabel_frame = gtk.Frame() + self.ResolutionLabel = gtk.Label("Resolution") + ResolutionLabel_frame.add(self.ResolutionLabel) + self.ResolutionValue = gtk.Label(self.QualityIndicators["RefinementResolution"]) + ResolutionBox_frame = gtk.Frame() + self.ResolutionBox = gtk.EventBox() + self.ResolutionBox.add(self.ResolutionValue) + ResolutionBox_frame.add(self.ResolutionBox) + + MolprobityScoreLabel_frame = gtk.Frame() + self.MolprobityScoreLabel = gtk.Label("MolprobityScore") + MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) + self.MolprobityScoreValue = gtk.Label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + MolprobityScoreBox_frame = gtk.Frame() + self.MolprobityScoreBox = gtk.EventBox() + self.MolprobityScoreBox.add(self.MolprobityScoreValue) + MolprobityScoreBox_frame.add(self.MolprobityScoreBox) + + RamachandranOutliersLabel_frame = gtk.Frame() + self.RamachandranOutliersLabel = gtk.Label("Rama Outliers") + RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) + self.RamachandranOutliersValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + RamachandranOutliersBox_frame = gtk.Frame() + self.RamachandranOutliersBox = gtk.EventBox() + self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) + RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) + + RamachandranFavoredLabel_frame = gtk.Frame() + self.RamachandranFavoredLabel = gtk.Label("Rama Favored") + RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) + self.RamachandranFavoredValue = gtk.Label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + RamachandranFavoredBox_frame = gtk.Frame() + self.RamachandranFavoredBox = gtk.EventBox() + self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) + RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) + + rmsdBondsLabel_frame = gtk.Frame() + self.rmsdBondsLabel = gtk.Label("rmsd(Bonds)") + rmsdBondsLabel_frame.add(self.rmsdBondsLabel) + self.rmsdBondsValue = gtk.Label(self.QualityIndicators["RefinementRmsdBonds"]) + rmsdBondsBox_frame = gtk.Frame() + self.rmsdBondsBox = gtk.EventBox() + self.rmsdBondsBox.add(self.rmsdBondsValue) + rmsdBondsBox_frame.add(self.rmsdBondsBox) + + rmsdAnglesLabel_frame = gtk.Frame() + self.rmsdAnglesLabel = gtk.Label("rmsd(Angles)") + rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) + self.rmsdAnglesValue = gtk.Label(self.QualityIndicators["RefinementRmsdAngles"]) + rmsdAnglesBox_frame = gtk.Frame() + self.rmsdAnglesBox = gtk.EventBox() + self.rmsdAnglesBox.add(self.rmsdAnglesValue) + rmsdAnglesBox_frame.add(self.rmsdAnglesBox) + + MatrixWeightLabel_frame = gtk.Frame() + self.MatrixWeightLabel = gtk.Label("Matrix Weight") + MatrixWeightLabel_frame.add(self.MatrixWeightLabel) + self.MatrixWeightValue = gtk.Label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + MatrixWeightBox_frame = gtk.Frame() + self.MatrixWeightBox = gtk.EventBox() + self.MatrixWeightBox.add(self.MatrixWeightValue) + MatrixWeightBox_frame.add(self.MatrixWeightBox) + + ligandIDLabel_frame = gtk.Frame() + self.ligandIDLabel = gtk.Label("Ligand ID") + ligandIDLabel_frame.add(self.ligandIDLabel) + self.ligandIDValue = gtk.Label(self.spider_plot_data["PANDDA_site_ligand_id"]) + ligandIDBox_frame = gtk.Frame() + self.ligandIDBox = gtk.EventBox() + self.ligandIDBox.add(self.ligandIDValue) + ligandIDBox_frame.add(self.ligandIDBox) + + ligand_occupancyLabel_frame = gtk.Frame() + self.ligand_occupancyLabel = gtk.Label("occupancy") + ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) + self.ligand_occupancyValue = gtk.Label( + self.spider_plot_data["PANDDA_site_occupancy"] + ) + ligand_occupancyBox_frame = gtk.Frame() + self.ligand_occupancyBox = gtk.EventBox() + self.ligand_occupancyBox.add(self.ligand_occupancyValue) + ligand_occupancyBox_frame.add(self.ligand_occupancyBox) + + ligand_BaverageLabel_frame = gtk.Frame() + self.ligand_BaverageLabel = gtk.Label("B average") + ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) + self.ligand_BaverageValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_average"] + ) + ligand_BaverageBox_frame = gtk.Frame() + self.ligand_BaverageBox = gtk.EventBox() + self.ligand_BaverageBox.add(self.ligand_BaverageValue) + ligand_BaverageBox_frame.add(self.ligand_BaverageBox) + + ligand_BratioSurroundingsLabel_frame = gtk.Frame() + self.ligand_BratioSurroundingsLabel = gtk.Label("B ratio") + ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) + self.ligand_BratioSurroundingsValue = gtk.Label( + self.spider_plot_data["PANDDA_site_B_ratio_residue_surroundings"] + ) + ligand_BratioSurroundingsBox_frame = gtk.Frame() + self.ligand_BratioSurroundingsBox = gtk.EventBox() + self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) + ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) + + ligand_RSCCLabel_frame = gtk.Frame() + self.ligand_RSCCLabel = gtk.Label("RSCC") + ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) + self.ligand_RSCCValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSCC"]) + ligand_RSCCBox_frame = gtk.Frame() + self.ligand_RSCCBox = gtk.EventBox() + self.ligand_RSCCBox.add(self.ligand_RSCCValue) + ligand_RSCCBox_frame.add(self.ligand_RSCCBox) + + ligand_rmsdLabel_frame = gtk.Frame() + self.ligand_rmsdLabel = gtk.Label("rmsd") + ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) + self.ligand_rmsdValue = gtk.Label(self.spider_plot_data["PANDDA_site_rmsd"]) + ligand_rmsdBox_frame = gtk.Frame() + self.ligand_rmsdBox = gtk.EventBox() + self.ligand_rmsdBox.add(self.ligand_rmsdValue) + ligand_rmsdBox_frame.add(self.ligand_rmsdBox) + + ligand_RSRLabel_frame = gtk.Frame() + self.ligand_RSRLabel = gtk.Label("RSR") + ligand_RSRLabel_frame.add(self.ligand_RSRLabel) + self.ligand_RSRValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSR"]) + ligand_RSRBox_frame = gtk.Frame() + self.ligand_RSRBox = gtk.EventBox() + self.ligand_RSRBox.add(self.ligand_RSRValue) + ligand_RSRBox_frame.add(self.ligand_RSRBox) + + ligand_RSZDLabel_frame = gtk.Frame() + self.ligand_RSZDLabel = gtk.Label("RSZD") + ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) + self.ligand_RSZDValue = gtk.Label(self.spider_plot_data["PANDDA_site_RSZD"]) + ligand_RSZDBox_frame = gtk.Frame() + self.ligand_RSZDBox = gtk.EventBox() + self.ligand_RSZDBox.add(self.ligand_RSZDValue) + ligand_RSZDBox_frame.add(self.ligand_RSZDBox) + + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame() + self.table_left = gtk.Table(8, 2, False) + self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) + self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) + self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) + self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) + self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) + self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) + self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) + self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) + self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) + self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) + self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) + self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) + self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) + self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) + self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) + self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) + frame.add(self.table_left) + hbox.add(frame) + + frame = gtk.Frame() + self.table_right = gtk.Table(8, 2, False) + self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) + self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) + self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) + self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) + self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) + self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) + self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) + self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) + self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) + self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) + self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) + self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) + self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) + self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) + self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) + frame.add(self.table_right) + hbox.add(frame) + + outer_frame.add(hbox) + self.vbox.add(outer_frame) + + hbox = gtk.HBox() + button = gtk.Button(label="Show MolProbity to-do list") + button.connect("clicked", self.show_molprobity_to_do) + hbox.add(button) + # --- ground state mean map --- + self.ground_state_mean_map_button = gtk.Button( + label="Show ground state mean map" + ) + self.ground_state_mean_map_button.connect( + "clicked", self.show_ground_state_mean_map + ) + hbox.add(self.ground_state_mean_map_button) + self.vbox.add(hbox) + + self.vbox.pack_start(frame) + + # SPACER + + ################################################################################ + # --- hbox for compound picture & spider_plot (formerly: refinement history) --- + frame = gtk.Frame() + self.hbox_for_info_graphics = gtk.HBox() + + # --- compound picture --- + compound_frame = gtk.Frame() + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image = gtk.Image() + self.image.set_from_pixbuf(self.pic) + compound_frame.add(self.image) + self.hbox_for_info_graphics.add(compound_frame) + + # --- Spider Plot --- + spider_plot_frame = gtk.Frame() + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image = gtk.Image() + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + spider_plot_frame.add(self.spider_plot_image) + self.hbox_for_info_graphics.add(spider_plot_frame) + + frame.add(self.hbox_for_info_graphics) + self.vbox.add(frame) + + outer_frame = gtk.Frame(label="Sample Navigator") + hboxSample = gtk.HBox() + + # --- crystal navigator combobox --- + frame = gtk.Frame() + self.vbox_sample_navigator = gtk.VBox() + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseXtal) + self.vbox_sample_navigator.add(self.cb) + # --- crystal navigator backward/forward button --- + self.PREVbutton = gtk.Button(label="<<<") + self.NEXTbutton = gtk.Button(label=">>>") + self.PREVbutton.connect("clicked", self.ChangeXtal, -1) + self.NEXTbutton.connect("clicked", self.ChangeXtal, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbutton) + hbox.pack_start(self.NEXTbutton) + self.vbox_sample_navigator.add(hbox) + frame.add(self.vbox_sample_navigator) + hboxSample.add(frame) + + # --- site navigator combobox --- + frame = gtk.Frame() + self.vbox_site_navigator = gtk.VBox() + self.cb_site = gtk.combo_box_new_text() + self.cb_site.connect("changed", self.ChooseSite) + self.vbox_site_navigator.add(self.cb_site) + # --- site navigator backward/forward button --- + self.PREVbuttonSite = gtk.Button(label="<<<") + self.NEXTbuttonSite = gtk.Button(label=">>>") + self.PREVbuttonSite.connect("clicked", self.ChangeSite, -1) + self.NEXTbuttonSite.connect("clicked", self.ChangeSite, +1) + hbox = gtk.HBox() + hbox.pack_start(self.PREVbuttonSite) + hbox.pack_start(self.NEXTbuttonSite) + self.vbox_site_navigator.add(hbox) + frame.add(self.vbox_site_navigator) + hboxSample.add(frame) + + outer_frame.add(hboxSample) + self.vbox.add(outer_frame) + + ################################################################################ + # --- current refinement stage --- + outer_frame = gtk.Frame() + hbox = gtk.HBox() + + frame = gtk.Frame(label="Analysis Status") + vbox = gtk.VBox() + self.experiment_stage_button_list = [] + for n, button in enumerate(self.experiment_stage): + if n == 0: + new_button = gtk.RadioButton(None, button[0]) + else: + new_button = gtk.RadioButton(new_button, button[0]) + new_button.connect( + "toggled", self.experiment_stage_button_clicked, button[1] + ) + vbox.pack_start(new_button, False, False, 0) + self.experiment_stage_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + # --- ligand confidence --- + frame = gtk.Frame(label="Ligand Confidence") + vbox = gtk.VBox() + self.ligand_confidence_button_list = [] + for n, criteria in enumerate(self.ligand_confidence_category): + if n == 0: + new_button = gtk.RadioButton(None, criteria) + else: + new_button = gtk.RadioButton(new_button, criteria) + new_button.connect( + "toggled", self.ligand_confidence_button_clicked, criteria + ) + vbox.pack_start(new_button, False, False, 0) + self.ligand_confidence_button_list.append(new_button) + frame.add(vbox) + hbox.pack_start(frame) + + outer_frame.add(hbox) + self.vbox.pack_start(outer_frame) + + # --- ligand modeling --- + frame = gtk.Frame(label="Ligand Modeling") + self.hbox_for_modeling = gtk.HBox() + self.merge_ligand_button = gtk.Button(label="Merge Ligand") + self.place_ligand_here_button = gtk.Button(label="Place Ligand here") + self.hbox_for_modeling.add(self.place_ligand_here_button) + self.place_ligand_here_button.connect("clicked", self.place_ligand_here) + self.hbox_for_modeling.add(self.merge_ligand_button) + self.merge_ligand_button.connect("clicked", self.merge_ligand_into_protein) + self.select_cpd_cb = gtk.combo_box_new_text() + self.select_cpd_cb.connect("changed", self.select_cpd) + self.hbox_for_modeling.add(self.select_cpd_cb) + frame.add(self.hbox_for_modeling) + self.vbox.pack_start(frame) + + # --- refinement & options --- + self.hbox_for_refinement = gtk.HBox() + self.REFINEbutton = gtk.Button(label="Refine") + self.RefinementParamsButton = gtk.Button(label="refinement parameters") + self.covalentLinksbutton = gtk.Button(label="covalent links\n-define-") + self.covalentLinksCreatebutton = gtk.Button( + label="covalent links\n-create & refine-" + ) + self.REFINEbutton.connect("clicked", self.REFINE) + self.hbox_for_refinement.add(self.REFINEbutton) + self.RefinementParamsButton.connect("clicked", self.RefinementParams) + self.covalentLinksbutton.connect("clicked", self.covalentLinkDef) + self.covalentLinksCreatebutton.connect("clicked", self.covalentLinkCreate) + self.hbox_for_refinement.add(self.RefinementParamsButton) + self.hbox_for_refinement.add(self.covalentLinksbutton) + self.hbox_for_refinement.add(self.covalentLinksCreatebutton) + self.vbox.add(self.hbox_for_refinement) + + # --- CANCEL button --- + self.CANCELbutton = gtk.Button(label="CANCEL") + self.CANCELbutton.connect("clicked", self.CANCEL) + self.vbox.add(self.CANCELbutton) + + self.window.add(self.vbox) + self.window.show_all() + + def CANCEL(self, widget): + self.window.destroy() + + def ChangeXtal(self, widget, data=None): + self.index = self.index + data + if self.index < 0: + self.index = 0 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def ChooseXtal(self, widget): + self.xtalID = str(widget.get_active_text()) + for n, item in enumerate(self.Todo): + if str(item[0]) == self.xtalID: + self.index = n + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + + self.refresh_site_combobox() + self.db_dict_mainTable = {} + self.db_dict_panddaTable = {} + if str(self.Todo[self.index][0]) is not None: + self.compoundID = str(self.Todo[self.index][1]) + self.refinement_outcome = str(self.Todo[self.index][5]) + self.update_RefinementOutcome_radiobutton() + if ( + self.xtalID not in self.siteDict + ): # i.e. we are not working with a PanDDA model + self.ligand_confidence = str(self.Todo[self.index][6]) + + self.RefreshData() + + def select_cpd(self, widget): + cpd = str(widget.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if "rhofit" in coot.molecule_name(imol) or "phenix" in coot.molecule_name( + imol + ): + molNameCIF = ( + coot.molecule_name(imol)[coot.molecule_name(imol).rfind("/") + 1 :] + .replace(".pdb", "") + .replace("_phenix", "") + .replace("_rhofit", "") + ) + else: + molNameCIF = molName + print(cpd, "-", imol, "-", coot.molecule_name(imol)) + if molName == cpd: + coot.set_mol_displayed(imol, 1) + print( + "reading", + os.path.join( + self.project_directory, + self.xtalID, + "compound", + molNameCIF + ".cif", + ), + ) + coot.read_cif_dictionary( + os.path.join( + self.project_directory, + self.xtalID, + "compound", + molNameCIF + ".cif", + ) + ) + else: + coot.set_mol_displayed(imol, 0) + + def update_RefinementOutcome_radiobutton(self): + # updating dataset outcome radiobuttons + current_stage = 0 + for i, entry in enumerate(self.experiment_stage): + if entry[1].split()[0] == self.refinement_outcome.split()[0]: + current_stage = i + break + for i, button in enumerate(self.experiment_stage_button_list): + if i == current_stage: + button.set_active(True) + break + + def update_LigandConfidence_radiobutton(self): + # updating ligand confidence radiobuttons + current_stage = 0 + for i, entry in enumerate(self.ligand_confidence_category): + print("--->", entry, self.ligand_confidence) + try: + if entry.split()[0] == self.ligand_confidence.split()[0]: + current_stage = i + break + except IndexError: + pass + for i, button in enumerate(self.ligand_confidence_button_list): + if i == current_stage: + button.set_active(True) + break + + def refresh_site_combobox(self): + # reset self.pandda_index + self.pandda_index = -1 + # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever + # be 100 sites + for n in range(-1, 100): + self.cb_site.remove_text(0) + self.site_index = "0" + self.event_index = "0" + # only repopulate if site exists + if self.xtalID in self.siteDict: + for item in sorted(self.siteDict[self.xtalID]): + self.cb_site.append_text( + "site: {0!s} - event: {1!s}".format(item[5], item[6]) + ) + + def ChangeSite(self, widget, data=None): + if self.xtalID in self.siteDict: + self.pandda_index = self.pandda_index + data + if self.pandda_index < 0: + self.pandda_index = 0 + if self.pandda_index >= len(self.siteDict[self.xtalID]): + self.pandda_index = 0 + self.cb_site.set_active(self.pandda_index) + + def ChooseSite(self, widget): + tmp = str(widget.get_active_text()) + print(self.siteDict) + print(self.site_index) + self.site_index = tmp.split()[1] + self.event_index = tmp.split()[4] + for n, item in enumerate(self.siteDict[self.xtalID]): + if item[5] == self.site_index and item[6] == self.event_index: + self.pandda_index = n + self.RefreshSiteData() + + def RefreshSiteData(self): + if self.pandda_index == -1: + self.merge_ligand_button.set_sensitive(True) + self.place_ligand_here_button.set_sensitive(True) + else: + self.merge_ligand_button.set_sensitive(False) + self.place_ligand_here_button.set_sensitive(False) + # and remove ligand molecule so that there is no temptation to merge it + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if self.compoundID + ".pdb" in coot.molecule_name(imol): + coot.close_molecule(imol) + + print("pandda index", self.pandda_index) + self.spider_plot = self.siteDict[self.xtalID][self.pandda_index][4] + print("new spider plot:", self.spider_plot) + self.event_map = self.siteDict[self.xtalID][self.pandda_index][0] + print("new event map:", self.event_map) + self.ligand_confidence = str(self.siteDict[self.xtalID][self.pandda_index][7]) + self.update_LigandConfidence_radiobutton() + site_x = float(self.siteDict[self.xtalID][self.pandda_index][1]) + site_y = float(self.siteDict[self.xtalID][self.pandda_index][2]) + site_z = float(self.siteDict[self.xtalID][self.pandda_index][3]) + print("new site coordinates:", site_x, site_y, site_z) + coot.set_rotation_centre(site_x, site_y, site_z) + + self.spider_plot_data = ( + self.db.get_db_pandda_dict_for_sample_and_site_and_event( + self.xtalID, self.site_index, self.event_index + ) + ) + print(">>>>> spider plot data", self.spider_plot_data) + self.ligandIDValue.set_label(self.spider_plot_data["PANDDA_site_ligand_id"]) + try: + self.ligand_occupancyValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_occupancy"]), 2)) + ) + except ValueError: + self.ligand_occupancyValue.set_label("-") + + try: + self.ligand_BaverageValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_B_average"]), 2)) + ) + except ValueError: + self.ligand_BaverageValue.set_label("-") + + try: + self.ligand_BratioSurroundingsValue.set_label( + str( + round( + float( + self.spider_plot_data[ + "PANDDA_site_B_ratio_residue_surroundings" + ] + ), + 2, + ) + ) + ) + except ValueError: + self.ligand_BratioSurroundingsValue.set_label("-") + + try: + self.ligand_RSCCValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSCC"]), 2)) + ) + except ValueError: + self.ligand_RSCCValue.set_label("-") + + try: + self.ligand_rmsdValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_rmsd"]), 2)) + ) + except ValueError: + self.ligand_rmsdValue.set_label("-") + + try: + self.ligand_RSRValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSR"]), 2)) + ) + except ValueError: + self.ligand_RSRValue.set_label("-") + + try: + self.ligand_RSZDValue.set_label( + str(round(float(self.spider_plot_data["PANDDA_site_RSZD"]), 2)) + ) + except ValueError: + self.ligand_RSZDValue.set_label("-") + + ################################################################################ + # delete old Event MAPs + if len(coot_utils_XChem.molecule_number_list()) > 0: + for imol in coot_utils_XChem.molecule_number_list(): + if "map.native.ccp4" in coot.molecule_name(imol): + coot.close_molecule(imol) + + ################################################################################ + # Spider plot + # Note: refinement history was shown instead previously + if os.path.isfile(self.spider_plot): + spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) + else: + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + ################################################################################ + # check for PANDDAs EVENT maps + if os.path.isfile(self.event_map): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.handle_read_ccp4_map((self.event_map), 0) + for imol in coot_utils_XChem.molecule_number_list(): + if self.event_map in coot.molecule_name(imol): + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + + def experiment_stage_button_clicked(self, widget, data=None): + self.db_dict_mainTable["RefinementOutcome"] = data + self.Logfile.insert( + "==> COOT: setting Refinement Outcome for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.create_or_remove_missing_records_in_depositTable( + self.xce_logfile, self.xtalID, "ligand_bound", self.db_dict_mainTable + ) + + def ligand_confidence_button_clicked(self, widget, data=None): + print("PANDDA_index", self.pandda_index) + if self.pandda_index == -1: + self.db_dict_mainTable["RefinementLigandConfidence"] = data + self.Logfile.insert( + "==> COOT: setting Ligand Confidence for " + + self.xtalID + + " to " + + str(data) + + " in mainTable of datasource" + ) + self.db.update_data_source(self.xtalID, self.db_dict_mainTable) + self.Todo[self.index][6] = data + else: + self.db_dict_panddaTable["PANDDA_site_confidence"] = data + self.Logfile.insert( + "==> COOT: setting Ligand Confidence for " + + self.xtalID + + " (site=" + + str(self.site_index) + + ", event=" + + str(self.event_index) + + ") to " + + str(data) + + " in panddaTable of datasource" + ) + self.db.update_site_event_panddaTable( + self.xtalID, self.site_index, self.event_index, self.db_dict_panddaTable + ) + self.siteDict[self.xtalID][self.pandda_index][7] = data + + def RefreshData(self): + # reset spider plot image + spider_plot_pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ) + ) + self.spider_plot_pic = spider_plot_pic.scale_simple( + 190, 190, gtk.gdk.INTERP_BILINEAR + ) + self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) + + # reset ground state mean map + self.ground_state_mean_map = "" + self.ground_state_mean_map_button.set_sensitive(False) + self.ground_state_mean_map_button.set_label("Show ground state mean map") + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + ): + self.ground_state_mean_map_button.set_sensitive(True) + self.ground_state_mean_map = os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-ground-state-mean-map.native.ccp4", + ) + + # initialize Refinement library + self.Refine = XChemRefine.Refine( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ) + self.Serial = XChemRefine.GetSerial(self.project_directory, self.xtalID) + self.panddaSerial = (4 - len(str(self.Serial))) * "0" + str(self.Serial) + if self.Serial == 1: + # i.e. no refinement has been done; data is probably straight out of dimple + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, self.pdb_style), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init_twin.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join(self.project_directory, self.xtalID, "init_twin.pdb"), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple_twin.pdb") + ): + print( + "==> XCE: updating quality indicators in data source for " + + self.xtalID + ) + XChemUtils.parse().update_datasource_with_PDBheader( + self.xtalID, + self.data_source, + os.path.join( + self.project_directory, self.xtalID, "dimple_twin.pdb" + ), + ) + XChemUtils.parse().update_datasource_with_phenix_validation_summary( + self.xtalID, self.data_source, "" + ) # '' because file does not exist + + # all this information is now updated in the datasource after each refinement + # cycle + self.QualityIndicators = self.db.get_db_dict_for_sample(self.xtalID) + + ################################################################################ + # history + # if the structure was previously refined, try to read the parameters + # self.hbox_for_info_graphics.remove(self.canvas) + if self.Serial > 1: + self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) + print("==> REFMAC params:", self.RefmacParams) + + ################################################################################ + # ligand files + # first remove old samples if present + print(">>>", self.mol_dict["ligand_stereo"]) + for n, item in enumerate(self.mol_dict["ligand_stereo"]): + print("__", item) + self.select_cpd_cb.remove_text(0) + print("done") + + ################################################################################ + # remove potential generic line which indicates a possible covalent link + coot.generic_object_clear(self.covLinkObject) + self.covLinkAtomSpec = None + + ################################################################################ + # update pdb & maps + + ################################################################################ + # delete old PDB and MAP files + # - get a list of all molecules which are currently opened in COOT + # - remove all molecules/ maps before loading a new set + if len(coot_utils_XChem.molecule_number_list()) > 0: + for item in coot_utils_XChem.molecule_number_list(): + coot.close_molecule(item) + + ################################################################################ + # read new PDB files + # read protein molecule after ligand so that this one is the active molecule + coot.set_nomenclature_errors_on_read("ignore") + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.compoundID + ".pdb") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ), + 0, + ) + self.mol_dict["ligand"] = imol + coot.read_cif_dictionary( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ) + self.select_cpd_cb.append_text(self.compoundID) + self.mol_dict["ligand_stereo"] = [] + self.mol_dict["ligand_stereo"].append(imol) + # ligands in compound directory + for cifFile in sorted( + glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + "compound", + self.compoundID + "_*.pdb", + ) + ) + ): + cif = cifFile[cifFile.rfind("/") + 1 :] + if "_with_H" in cif: + continue + self.select_cpd_cb.append_text(cif.replace(".pdb", "")) + imol = coot.handle_read_draw_molecule_with_recentre(cifFile, 0) + self.mol_dict["ligand_stereo"].append(imol) + coot.set_mol_displayed(imol, 0) + # autofitted ligands + for pdbFile in sorted( + glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + "autofit_ligand", + "*", + "*.pdb", + ) + ) + ): + autofitRun = pdbFile.split("/")[len(pdbFile.split("/")) - 2] + if pdbFile.endswith(autofitRun + ".pdb"): + self.select_cpd_cb.append_text(autofitRun) + imol = coot.handle_read_draw_molecule_with_recentre(pdbFile, 0) + self.mol_dict["ligand_stereo"].append(imol) + coot.set_mol_displayed(imol, 0) + self.select_cpd_cb.set_sensitive(True) + self.select_cpd_cb.set_active(0) + else: + print("no compound found in sample directory") + self.select_cpd_cb.set_sensitive(False) + + if not os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.pdb_style) + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, self.pdb_style), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init_twin.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "init_twin.pdb"), 0 + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple_twin.pdb") + ): + os.chdir(os.path.join(self.project_directory, self.xtalID)) + imol = coot.handle_read_draw_molecule_with_recentre( + os.path.join(self.project_directory, self.xtalID, "dimple_twin.pdb"), 0 + ) + else: + self.go_to_next_xtal() + self.mol_dict["protein"] = imol + + # read any one event map if present + for event_map in glob.glob( + os.path.join( + self.project_directory, + self.xtalID, + self.xtalID + "-event_*.native.ccp4", + ) + ): + coot.handle_read_ccp4_map((event_map), 0) + coot.set_contour_level_in_sigma(imol, 2) + coot.set_last_map_colour(0.74, 0.44, 0.02) + break + + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) or coot.molecule_name(item).endswith(self.pdb_style): + # master switch to show symmetry molecules + coot.set_show_symmetry_master(1) + coot.set_show_symmetry_molecule(item, 1) # show symm for model + + ################################################################################ + # read fofc maps + # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map + # read 2fofc map last so that one can change its contour level + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "2fofc_twin.map") + ): + coot.set_colour_map_rotation_on_read_pdb(0) + coot.set_default_initial_contour_level_for_difference_map(3) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "fofc_twin.map"), 1 + ) + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map( + os.path.join(self.project_directory, self.xtalID, "2fofc_twin.map"), 0 + ) + coot.set_last_map_colour(0, 0, 1) + else: + # try to open mtz file with same name as pdb file + coot.set_default_initial_contour_level_for_map(1) + if os.path.isfile( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, self.mtz_style) + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "init_twin.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "init_twin.mtz") + ) + elif os.path.isfile( + os.path.join(self.project_directory, self.xtalID, "dimple_twin.mtz") + ): + coot.auto_read_make_and_draw_maps( + os.path.join(self.project_directory, self.xtalID, "dimple_twin.mtz") + ) + + ################################################################################ + # update Quality Indicator table + try: + self.RRfreeValue.set_label( + str(round(float(self.QualityIndicators["RefinementRcryst"]), 3)) + + " / " + + str(round(float(self.QualityIndicators["RefinementRfree"]), 3)) + ) + except ValueError: + self.RRfreeValue.set_label("-") + + try: + self.RRfreeBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRfreeTraficLight"] + ), + ) + except ValueError: + pass + self.ResolutionValue.set_label(self.QualityIndicators["RefinementResolution"]) + try: + self.ResolutionBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementResolutionTL"]), + ) + except ValueError: + pass + self.MolprobityScoreValue.set_label( + self.QualityIndicators["RefinementMolProbityScore"] + ) + try: + self.MolprobityScoreBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementMolProbityScoreTL"] + ), + ) + except ValueError: + pass + self.RamachandranOutliersValue.set_label( + self.QualityIndicators["RefinementRamachandranOutliers"] + ) + try: + self.RamachandranOutliersBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranOutliersTL"] + ), + ) + except ValueError: + pass + self.RamachandranFavoredValue.set_label( + self.QualityIndicators["RefinementRamachandranFavored"] + ) + try: + self.RamachandranFavoredBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse( + self.QualityIndicators["RefinementRamachandranFavoredTL"] + ), + ) + except ValueError: + pass + self.rmsdBondsValue.set_label(self.QualityIndicators["RefinementRmsdBonds"]) + try: + self.rmsdBondsBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdBondsTL"]), + ) + except ValueError: + pass + self.rmsdAnglesValue.set_label(self.QualityIndicators["RefinementRmsdAngles"]) + try: + self.rmsdAnglesBox.modify_bg( + gtk.STATE_NORMAL, + gtk.gdk.color_parse(self.QualityIndicators["RefinementRmsdAnglesTL"]), + ) + except ValueError: + pass + self.MatrixWeightValue.set_label( + self.QualityIndicators["RefinementMatrixWeight"] + ) + + try: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".png" + ) + ) + except gobject.GError: + pic = gtk.gdk.pixbuf_new_from_file( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_COMPOUND_IMAGE_AVAILABLE.png", + ) + ) + self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) + self.image.set_from_pixbuf(self.pic) + + def go_to_next_xtal(self): + self.index += 1 + if self.index >= len(self.Todo): + self.index = len(self.Todo) + self.cb.set_active(self.index) + + def REFINE(self, widget): + self.start_refinement() + + def start_refinement(self): + if not os.path.isdir( + os.path.join(self.project_directory, self.xtalID, "cootOut") + ): + os.mkdir(os.path.join(self.project_directory, self.xtalID, "cootOut")) + # create folder for new refinement cycle + try: + self.Logfile.insert( + "==> COOT: trying to make folder: %s" + % os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + ) + ) + os.mkdir( + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + ) + ) + except OSError: + self.Logfile.warning("==> COOT: folder exists; will overwrite contents!") + self.Logfile.warning( + "==> COOT: it is advised to check the sample directory" + " as this might be a symptom for a PDB file problem" + ) + + ####################################################### + # write PDB file + # now take protein pdb file and write it to newly create Refine_ folder + # note: the user has to make sure that the ligand file was merged into main file + foundPDB = False + for item in coot_utils_XChem.molecule_number_list(): + if coot.molecule_name(item).endswith(self.pdb_style): + foundPDB = True + break + elif coot.molecule_name(item).endswith("refine.split.bound-state.pdb"): + foundPDB = True + break + elif coot.molecule_name(item).endswith("init_twin.pdb"): + foundPDB = True + break + elif coot.molecule_name(item).endswith("dimple_twin.pdb"): + foundPDB = True + break + if foundPDB: + coot.write_pdb_file( + item, + os.path.join( + self.project_directory, + self.xtalID, + "cootOut", + "Refine_" + str(self.Serial), + "in.pdb", + ), + ) + + self.Refine.RunBuster( + self.Serial, + self.external_software, + self.xce_logfile, + self.covLinkAtomSpec, + get_token(fetch_password_gtk), + ) + self.index += 1 + if self.index >= len(self.Todo): + self.index = 0 + self.cb.set_active(self.index) + + def RefinementParams(self, widget): + print("\n==> XCE: changing refinement parameters") + self.RefmacParams = XChemRefine.RefineParams( + self.project_directory, self.xtalID, self.compoundID, self.data_source + ).RefmacRefinementParams(self.RefmacParams) + + def covalentLinkDef(self, widget): + coot.user_defined_click_py(2, self.show_potential_link) + + def show_potential_link(self, *clicks): + # first find imol of protein molecule + # it's a prerequisite that the ligand is merged into the protein + imol_protein = None + for imol in coot_utils_XChem.molecule_number_list(): + print(">", coot.molecule_name(imol)) + if ( + coot.molecule_name(imol).endswith(self.pdb_style) + or coot.molecule_name(imol).endswith("init_twin.pdb") + or coot.molecule_name(imol).endswith("dimple_twin.pdb") + or coot.molecule_name(imol).endswith( + self.pdb_style.replace(".pdb", "") + ".split.bound-state.pdb" + ) + ): + imol_protein = imol + break + + print("please click on the two atoms you want to link") + if len(clicks) == 2: + click_1 = clicks[0] + click_2 = clicks[1] + imol_1 = click_1[1] + imol_2 = click_2[1] + print("imolp", imol, "imo11", imol_1, "imol2", imol_2) + if imol_1 == imol_2 and imol_1 == imol_protein: + print("click_1", click_1) + self.covLinkAtomSpec = None + xyz_1 = coot.atom_info_string_py( + click_1[1], + click_1[2], + click_1[3], + click_1[4], + click_1[5], + click_1[6], + ) + residue_1 = coot.residue_name( + click_1[1], click_1[2], click_1[3], click_1[4] + ) + xyz_2 = coot.atom_info_string_py( + click_2[1], + click_2[2], + click_2[3], + click_2[4], + click_2[5], + click_2[6], + ) + residue_2 = coot.residue_name( + click_2[1], click_2[2], click_2[3], click_2[4] + ) + thick = 4 + coot.to_generic_object_add_line( + self.covLinkObject, + "yellowtint", + thick, + xyz_1[3], + xyz_1[4], + xyz_1[5], + xyz_2[3], + xyz_2[4], + xyz_2[5], + ) + coot.set_display_generic_object(self.covLinkObject, 1) + self.covLinkAtomSpec = [ + imol_protein, + click_1, + click_2, + residue_1, + residue_2, + ] + else: + print( + "error: both atoms must belong to the same object;" + " did you merge the ligand with your protein?" + ) + + def covalentLinkCreate(self, widget): + if self.covLinkAtomSpec is not None: + imol = self.covLinkAtomSpec[0] + atom1 = self.covLinkAtomSpec[1][1:] + atom2 = self.covLinkAtomSpec[2][1:] + residue_1 = self.covLinkAtomSpec[3] + residue_2 = self.covLinkAtomSpec[4] + coot.make_link(imol, atom1, atom2, residue_1 + "-" + residue_2, 1.7) + coot.generic_object_clear(self.covLinkObject) + self.start_refinement() + else: + print("error: no covalent link defined") + + def set_selection_mode(self, widget): + self.selection_mode = widget.get_active_text() + + def get_samples_to_look_at(self, widget): + if self.selection_mode == "": + self.status_label.set_text("select model stage") + return + self.status_label.set_text("checking datasource for samples... ") + # first remove old samples if present + if len(self.Todo) != 0: + for n, item in enumerate(self.Todo): + self.cb.remove_text(0) + self.Todo = [] + self.siteDict = {} + self.Todo, self.siteDict = self.db.get_todoList_for_coot(self.selection_mode) + self.status_label.set_text("found {0!s} samples".format(len(self.Todo))) + # refresh sample CB + for item in sorted(self.Todo): + self.cb.append_text("{0!s}".format(item[0])) + if self.siteDict == {}: + self.cb_site.set_sensitive(False) + self.PREVbuttonSite.set_sensitive(False) + self.NEXTbuttonSite.set_sensitive(False) + else: + self.cb_site.set_sensitive(True) + self.PREVbuttonSite.set_sensitive(True) + self.NEXTbuttonSite.set_sensitive(True) + + def update_plot(self, refinement_cycle, Rfree, Rcryst): + fig = Figure(figsize=(2, 2), dpi=50) + Plot = fig.add_subplot(111) + Plot.set_ylim([0, max(Rcryst + Rfree)]) + Plot.set_xlabel("Refinement Cycle", fontsize=12) + Plot.plot(refinement_cycle, Rfree, label="Rfree", linewidth=2) + Plot.plot(refinement_cycle, Rcryst, label="Rcryst", linewidth=2) + Plot.legend( + bbox_to_anchor=(0.0, 1.02, 1.0, 0.102), + loc=3, + ncol=2, + mode="expand", + borderaxespad=0.0, + fontsize=12, + ) + return fig + + def place_ligand_here(self, widget): + cpd = str(self.select_cpd_cb.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if molName == cpd: + print("===> XCE: moving ligand to pointer") + coot_utils_XChem.move_molecule_here(imol) + print("LIGAND: ", molName) + + def merge_ligand_into_protein(self, widget): + cpd = str(self.select_cpd_cb.get_active_text()) + for imol in coot_utils_XChem.molecule_number_list(): + if imol not in self.mol_dict["ligand_stereo"]: + continue + molName = coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ].replace(".pdb", "") + if molName == cpd: + print("===> XCE: merge ligand into protein structure -->", cpd) + coot.merge_molecules_py([imol], self.mol_dict["protein"]) + if "rhofit" in coot.molecule_name( + imol + ) or "phenix" in coot.molecule_name(imol): + molName = ( + coot.molecule_name(imol)[ + coot.molecule_name(imol).rfind("/") + 1 : + ] + .replace(".pdb", "") + .replace("_phenix", "") + .replace("_rhofit", "") + ) + if os.path.isfile( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".cif" + ) + ): + os.system( + "/bin/rm %s" + % os.path.join( + self.project_directory, + self.xtalID, + self.compoundID + ".cif", + ) + ) + print( + "XCE: changing directory", + os.path.join(self.project_directory, self.xtalID), + ) + os.chdir(os.path.join(self.project_directory, self.xtalID)) + print( + "XCE: changing symlink ln -s %s %s.cif" + % (os.path.join("compound", molName + ".cif"), self.compoundID) + ) + os.system( + "ln -s %s %s.cif" + % (os.path.join("compound", molName + ".cif"), self.compoundID) + ) + if os.path.isfile( + os.path.join( + self.project_directory, self.xtalID, self.compoundID + ".pdb" + ) + ): + os.system( + "/bin/rm %s" + % os.path.join( + self.project_directory, + self.xtalID, + self.compoundID + ".pdb", + ) + ) + print( + "XCE: changing directory", + os.path.join(self.project_directory, self.xtalID), + ) + os.chdir(os.path.join(self.project_directory, self.xtalID)) + print( + "XCE: changing symlink ln -s %s %s.pdb" + % (os.path.join("compound", molName + ".pdb"), self.compoundID) + ) + os.system( + "ln -s %s %s.pdb" + % (os.path.join("compound", molName + ".pdb"), self.compoundID) + ) + print("===> XCE: deleting ligand molecule", molName) + coot.close_molecule(imol) + + self.select_cpd_cb.set_sensitive(False) + + def show_molprobity_to_do(self, widget): + print(self.panddaSerial) + AdjPanddaSerial = (4 - len(str(self.Serial))) * "0" + str( + int(self.panddaSerial) - 1 + ) + print( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.panddaSerial), + "molprobity_coot.py", + ) + ) + if os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + elif os.path.isfile( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(AdjPanddaSerial), + "molprobity_coot.py", + ) + ): + print("==> XCE: running MolProbity Summary for", self.xtalID) + coot.run_script( + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(AdjPanddaSerial), + "molprobity_coot.py", + ) + ) + else: + print( + "==> XCE: cannot find " + + os.path.join( + self.project_directory, + self.xtalID, + "Refine_" + str(self.Serial - 1), + "molprobity_coot.py", + ) + ) + + def show_ground_state_mean_map(self, widget): + if widget.get_label().startswith("Show"): + loaded = False + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 1) + loaded = True + break + if not loaded: + coot.set_default_initial_contour_level_for_map(1) + coot.handle_read_ccp4_map(self.ground_state_mean_map, 0) + coot.set_last_map_colour(0.6, 0.6, 0) + widget.set_label("Undisplay ground state mean map") + else: + for imol in coot_utils_XChem.molecule_number_list(): + if "ground-state-mean-map" in coot.molecule_name(imol): + coot.set_map_displayed(imol, 0) + widget.set_label("Show ground state mean map") + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import coot_utils_XChem + from xce.lib import XChemDB + from xce.lib import XChemLog + from xce.lib import XChemRefine + from xce.lib import XChemUtils + from xce.lib.cluster.slurm import get_token, fetch_password_gtk + + GUI().StartGUI() diff --git a/gui_scripts/datasets_tab.py b/gui_scripts/datasets_tab.py deleted file mode 100755 index 52d98955..00000000 --- a/gui_scripts/datasets_tab.py +++ /dev/null @@ -1,231 +0,0 @@ -import sys, os -from PyQt4 import QtGui, QtCore, QtWebKit - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'lib')) - -import layout - -import XChemMain - - -class DatasetsTab(): - def __init__(self): - self.layout_funcs = layout.LayoutFuncs() - - def setup(self, xce_object): - ################################################################################################################ - # # - # DATASETS TAB # - # # - ################################################################################################################ - # define subtab list, widget and dict - datasets_tab_list = ['Summary', 'Reprocess'] - xce_object.datasets_tab_widget = QtGui.QTabWidget() - xce_object.datasets_tab_dict = {} - - # make subtabs - self.layout_funcs.make_tab_dict(datasets_tab_list, xce_object.datasets_tab_widget, xce_object.datasets_tab_dict) - - # main body - things that are always displayed - # add a container to hold everythting and add to main tab layout - xce_object.datasets_data_collection_vbox = QtGui.QVBoxLayout() - - # add a horizontal box to hold option to autocheck for new data - xce_object.autocheck_hbox = QtGui.QHBoxLayout() - - # checkbox for autocollect - xce_object.check_for_new_data_collection = QtGui.QCheckBox('Check for new data collection every two minutes') - xce_object.check_for_new_data_collection = QtGui.QCheckBox('Check for new data collection every two minutes') - self.layout_funcs.add_checkbox(xce_object, xce_object.check_for_new_data_collection, - 'xce_object.continously_check_for_new_data_collection') - - # select target dropdown - select_target_label = QtGui.QLabel('Select Target: ') - select_target_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) - xce_object.target_selection_combobox = QtGui.QComboBox() - xce_object.populate_target_selection_combobox(xce_object.target_selection_combobox) - xce_object.target_selection_combobox.activated[str].connect(xce_object.target_selection_combobox_activated) - xce_object.target = str(xce_object.target_selection_combobox.currentText()) - - # array defining order of xce_objects to add - xce_object.autocheck_hbox_widgets = [xce_object.check_for_new_data_collection, select_target_label, - xce_object.target_selection_combobox] - - self.layout_funcs.add_to_box(xce_object.autocheck_hbox, - xce_object.autocheck_hbox_widgets) # add xce_objects in order - - # add target dropdown to top bar - xce_object.datasets_data_collection_vbox.addLayout(xce_object.autocheck_hbox) - - # summary sub-tab - # table - xce_object.datasets_summary_table = QtGui.QTableWidget() - - xce_object.datasets_summary_table.resizeRowsToContents() - xce_object.datasets_summary_table.resizeColumnsToContents() - xce_object.datasets_summary_table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - xce_object.datasets_summary_table.cellClicked.connect(xce_object.show_results_from_all_pipelines) - - self.layout_funcs.table_setup(xce_object.datasets_summary_table, xce_object.datasets_summary_table_columns) - xce_object.datasets_summarys_vbox_for_table = QtGui.QVBoxLayout() # setup layout to hold table - xce_object.datasets_summarys_vbox_for_table.addWidget(xce_object.datasets_summary_table) # add table to layout - xce_object.datasets_summarys_vbox_for_details = QtGui.QVBoxLayout() # vbox for details - xce_object.data_collection_details_currently_on_display = None # switch for displaying/updating table - - xce_object.datasets_data_collection_vbox.addWidget(xce_object.datasets_tab_widget) # add subtab to main tab - - # reprocessing sub-tab - # top options - # data collection label - dc_label = QtGui.QLabel('Data collection directory: ') - dc_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) # align left and centre of container - xce_object.diffraction_data_dir_label = QtGui.QLabel( - xce_object.diffraction_data_directory) # add directory as text - xce_object.diffraction_data_dir_label.setAlignment( - QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) # align as above - - # select label - select_button = QtGui.QPushButton("Select") - select_button.clicked.connect(xce_object.select_diffraction_data_directory) # attach file open dialogue - - # search button - search_button = QtGui.QPushButton("Search Datasets") - search_button.clicked.connect(xce_object.search_for_datasets) # search for datasets in the selected directory - - # search info - xce_object.diffraction_data_search_label = QtGui.QLabel(xce_object.diffraction_data_search_info) - - # translate label - translate_label = QtGui.QLabel('Translate: datasetID -> sampleID') - translate_label.setAlignment(QtCore.Qt.AlignCenter) # align in centre of container - - # CSV button - csv_button = QtGui.QPushButton('Open CSV') - csv_button.setStyleSheet("QPushButton { padding: 1px; margin: 1px }") - csv_button.clicked.connect(xce_object.translate_datasetID_to_sampleID) # open the relevant csv file - - # create hbox to hold everything and add widgets to it - xce_object.hbox_select = QtGui.QHBoxLayout() # top options box - xce_object.hbox_select_widgets = [dc_label, xce_object.diffraction_data_dir_label, select_button, search_button, - xce_object.diffraction_data_search_label, - translate_label, - csv_button] # array defining order of xce_objects to be added - self.layout_funcs.add_to_box(xce_object.hbox_select, xce_object.hbox_select_widgets) # add xce_objects in order - - # frame to hold everything - frame_select = QtGui.QFrame() - frame_select.setLayout(xce_object.hbox_select) # apply to containing frame - - # table - main body - xce_object.datasets_reprocess_table = QtGui.QTableWidget() - self.layout_funcs.table_setup(xce_object.datasets_reprocess_table, - xce_object.datasets_reprocess_columns) # setup - - # create context menu - no idea where this lives... - xce_object.popMenu_for_datasets_reprocess_table = QtGui.QMenu() - run_xia2_on_selected = QtGui.QAction("mark selected for reprocessing", xce_object.window) - run_xia2_on_selected.triggered.connect(xce_object.select_sample_for_xia2) - xce_object.popMenu_for_datasets_reprocess_table.addAction(run_xia2_on_selected) - xce_object.datasets_reprocess_table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - xce_object.datasets_reprocess_table.customContextMenuRequested.connect( - xce_object.on_context_menu_reprocess_data) - - # options at bottom of tab - # data processing label - label = QtGui.QLabel('Data processing protocol: ') - label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) - - # option checkboxes - xce_object.xia2_3d_checkbox = QtGui.QCheckBox('xia2 3d') - xce_object.xia2_3dii_checkbox = QtGui.QCheckBox('xia2 3dii') - xce_object.xia2_dials_checkbox = QtGui.QCheckBox('Dials') - - # spacegroup label - sg_label = QtGui.QLabel('Space Group:') - - # spacegroup dropdown menu - xce_object.reprocess_space_group_comboxbox = QtGui.QComboBox() - xce_object.reprocess_space_group_comboxbox.addItem('ignore') - for sg in XChemMain.space_group_list(): - xce_object.reprocess_space_group_comboxbox.addItem(sg) - - # mtz label - mtz_label = QtGui.QLabel('Reference MTZ:') - - # file label - xce_object.reprocess_reference_mtz_file_label = QtGui.QLabel(xce_object.diffraction_data_reference_mtz) - - # select button - select_button = QtGui.QPushButton("Select") - select_button.clicked.connect(xce_object.select_reprocess_reference_mtz) - - # define order of widgets to be added to options hbox - hbox_options_widgets = [label, xce_object.xia2_3d_checkbox, xce_object.xia2_3dii_checkbox, - xce_object.xia2_dials_checkbox, sg_label, xce_object.reprocess_space_group_comboxbox, - mtz_label, xce_object.reprocess_reference_mtz_file_label, select_button] - - # create hbox, add everything to it and then put it in a frame - hbox_options = QtGui.QHBoxLayout() - self.layout_funcs.add_to_box(hbox_options, hbox_options_widgets) - - frame_options = QtGui.QFrame() - frame_options.setLayout(hbox_options) - - # following are contained in vboxes - # res limit isig label - label = QtGui.QLabel('Res.\nLimit:\nMn') - label.setAlignment(QtCore.Qt.AlignCenter) - - # res limit isig dropdown menu - xce_object.reprocess_isigma_combobox = QtGui.QComboBox() - misigma = ['default', '4', '3', '2.5', '2', '1.5', '1', '0.5'] - self.layout_funcs.populate_combobox(misigma, xce_object.reprocess_isigma_combobox) - xce_object.reprocess_isigma_combobox.setCurrentIndex(0) - xce_object.reprocess_isigma_combobox.setStyleSheet(" QComboBox { padding: 1px; margin: 1px }") - - # create vertical box to add labels and dropdowns to, create box and put in frame - vbox_isigma = QtGui.QVBoxLayout() - vbox_isigma_widgets = [label, xce_object.reprocess_isigma_combobox] - self.layout_funcs.add_to_box(vbox_isigma, vbox_isigma_widgets) - frame_isigma = QtGui.QFrame() - frame_isigma.setLayout(vbox_isigma) - - # res limit cc half label - res_cc_label = QtGui.QLabel('Res.\nLimit:\nCC 1/2') - res_cc_label.setAlignment(QtCore.Qt.AlignCenter) - - # res limit cc half dropdown - xce_object.reprocess_cc_half_combobox = QtGui.QComboBox() - cc_half = ['default', '0.9', '0.8', '0.7', '0.6', '0.5', '0.4', '0.3', '0.2', '0.1'] - self.layout_funcs.populate_combobox(cc_half, xce_object.reprocess_cc_half_combobox) - xce_object.reprocess_cc_half_combobox.setCurrentIndex(0) - xce_object.reprocess_cc_half_combobox.setStyleSheet(" QComboBox { padding: 1px; margin: 1px }") - - # create a vbox for label and dropdown, and add items to it - vbox_cc_half = QtGui.QVBoxLayout() - vbox_cc_half_widgets = [res_cc_label, xce_object.reprocess_cc_half_combobox] - self.layout_funcs.add_to_box(vbox_cc_half, vbox_cc_half_widgets) - - # create frame to hold everything and add vbox - frame_cc_half = QtGui.QFrame() - frame_cc_half.setLayout(vbox_cc_half) - - # create a hbox to hold the bottom frames and add everything - data_protocol_hbox = QtGui.QHBoxLayout() - data_protocol_hbox_widgets = [frame_options, frame_isigma, frame_cc_half] - self.layout_funcs.add_to_box(data_protocol_hbox, data_protocol_hbox_widgets) - - bottom_options_frame = QtGui.QFrame() # create frame to hold everything (horizontal) - bottom_options_frame.setLayout(data_protocol_hbox) - - # code below sets final layout for whole subtab - xce_object.reprocess_vbox = QtGui.QVBoxLayout() # box to hold reprocessing subtab content - xce_object.reprocess_hbox_widgets = [frame_select, xce_object.datasets_reprocess_table, bottom_options_frame] - self.layout_funcs.add_to_box(xce_object.reprocess_vbox, xce_object.reprocess_hbox_widgets) - - - - - - diff --git a/gui_scripts/deposition_tab.py b/gui_scripts/deposition_tab.py deleted file mode 100755 index dfa5ded9..00000000 --- a/gui_scripts/deposition_tab.py +++ /dev/null @@ -1,241 +0,0 @@ -import sys, os -from PyQt4 import QtGui, QtCore, QtWebKit - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'lib')) - -import layout -import XChemToolTips - - -class DepositionTab(): - def __init__(self): - self.layout_funcs = layout.LayoutFuncs() - - def setup(self, xce_object): - ################################################################################################################ - # # - # DEPOSITION TAB # - # # - ################################################################################################################ - xce_object.deposition_vbox = QtGui.QVBoxLayout() - - scroll = QtGui.QScrollArea() - xce_object.deposition_vbox.addWidget(scroll) - scrollContent = QtGui.QWidget(scroll) - scrollLayout = QtGui.QVBoxLayout(scrollContent) - scrollContent.setLayout(scrollLayout) - - # deposition page heading - deposition_page_heading = self.layout_funcs.add_depo_heading('Group deposition of bound-state structures & ground-state model') - deposition_page_heading.setStyleSheet("font: bold 40pt Arial") - - deposition_page_introduction = QtGui.QLabel(XChemToolTips.deposition_introduction()) - deposition_page_introduction_link = QtGui.QLabel(XChemToolTips.deposition_introduction_link()) - deposition_page_introduction_link.setOpenExternalLinks(True) - - # - # bound-state depostion - # - - deposition_bound_state_heading = self.layout_funcs.add_depo_heading('Group deposition of bound-state structures') - deposition_bound_state_heading.setStyleSheet("font: bold 20pt Arial") - - deposition_bound_state_prerequisites = self.layout_funcs.add_depo_heading('Prerequisites') - deposition_bound_state_prerequisites.setStyleSheet("font: italic bold 17pt Arial") - - deposition_bound_state_prerequisites_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_bound_state_prerequisites()) - - deposition_bound_state_preparation = self.layout_funcs.add_depo_heading('Procedure') - deposition_bound_state_preparation.setStyleSheet("font: italic bold 17pt Arial ") - - deposition_bound_state_preparation_step_one_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_bound_state_preparation_step_one_text()) - - xce_object.deposition_bounnd_state_preparation_ignore_event_map = QtGui.QCheckBox(XChemToolTips.deposition_bounnd_state_preparation_ignore_event_map()) - - prepare_mmcif_button = QtGui.QPushButton('prepare mmcif') - prepare_mmcif_button.clicked.connect(xce_object.prepare_models_for_deposition_ligand_bound) - prepare_mmcif_button.setMaximumWidth(200) - - deposition_bound_state_preparation_step_two_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_bound_state_preparation_step_two_text()) - - copy_mmcif_button = QtGui.QPushButton('copy mmcif') - copy_mmcif_button.clicked.connect(xce_object.prepare_for_group_deposition_upload_ligand_bound) - copy_mmcif_button.setMaximumWidth(200) - - pdb_group_deposition_instruction_one = self.layout_funcs.add_depo_text(XChemToolTips.pdb_group_deposition_instruction_one()) - - pdb_group_deposition_link = QtGui.QLabel(XChemToolTips.pdb_group_deposition_link()) - pdb_group_deposition_link.setOpenExternalLinks(True) - - pdb_group_deposition_link_two = QtGui.QLabel(XChemToolTips.pdb_group_deposition_link()) - pdb_group_deposition_link_two.setOpenExternalLinks(True) - - pdb_group_deposition_instruction_two = self.layout_funcs.add_depo_text(XChemToolTips.pdb_group_deposition_instruction_two()) - pdb_group_deposition_instruction_two_two = self.layout_funcs.add_depo_text(XChemToolTips.pdb_group_deposition_instruction_two()) - - - # - # ground-state depostion - # - - deposition_ground_state_heading = self.layout_funcs.add_depo_heading('Group deposition of ground-state model') - deposition_ground_state_heading.setStyleSheet("font: bold 20pt Arial") - - - - deposition_ground_state_prerequisites = self.layout_funcs.add_depo_heading('Prerequisites') - deposition_ground_state_prerequisites.setStyleSheet("font: italic bold 17pt Arial") - - deposition_ground_state_prerequisites_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_prerequisites()) - - deposition_ground_state_preparation = self.layout_funcs.add_depo_heading('Procedure') - deposition_ground_state_preparation.setStyleSheet("font: italic bold 17pt Arial ") - - deposition_ground_state_preparation_step_one_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_one_text()) - - ground_state_pdb_button = QtGui.QPushButton('Select PDB file') - ground_state_pdb_button.clicked.connect(xce_object.select_ground_state_pdb) - ground_state_pdb_button.setMaximumWidth(200) - xce_object.ground_state_pdb_button_label = QtGui.QLabel('') - xce_object.ground_state_pdb_button_label.setStyleSheet('color: blue') - - deposition_ground_state_log_info = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_log_info()) - - deposition_ground_state_preparation_step_two_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_two_text()) - - ground_state_mtz_button = QtGui.QPushButton('Select MTZ file') - ground_state_mtz_button.clicked.connect(xce_object.select_ground_state_mtz) - ground_state_mtz_button.setMaximumWidth(200) - xce_object.ground_state_mtz_button_label = QtGui.QLabel('') - xce_object.ground_state_mtz_button_label.setStyleSheet('color: blue') - - deposition_ground_state_preparation_step_three_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_three_text()) - xce_object.ground_state_pandda_directory_label = QtGui.QLabel(xce_object.panddas_directory) - xce_object.ground_state_pandda_directory_label.setStyleSheet('color: blue') - - deposition_ground_state_preparation_step_four_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_four_text()) - - add_ground_state_db_button = QtGui.QPushButton('Add to database') - add_ground_state_db_button.clicked.connect(xce_object.add_ground_state_db) - add_ground_state_db_button.setMaximumWidth(200) - - deposition_ground_state_preparation_step_five_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_five_text()) - - deposition_ground_state_preparation_step_six_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_six_text()) - - prepare_ground_state_mmcif_button = QtGui.QPushButton('Prepare mmcif') - prepare_ground_state_mmcif_button.clicked.connect(xce_object.prepare_ground_state_mmcif) - prepare_ground_state_mmcif_button.setMaximumWidth(200) - - deposition_ground_state_preparation_step_seven_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_seven_text()) - - copy_apo_mmcif_button = QtGui.QPushButton('copy mmcif') - copy_apo_mmcif_button.clicked.connect(xce_object.prepare_for_group_deposition_upload_ground_state) - copy_apo_mmcif_button.setMaximumWidth(200) - - deposition_ground_state_preparation_step_eight_text = self.layout_funcs.add_depo_text(XChemToolTips.deposition_ground_state_preparation_step_eight_text()) - - - # - # after ligand_bound depostion - # - - after_deposition_heading = self.layout_funcs.add_depo_heading('After deposition of ligand-bound structures') - after_deposition_heading.setStyleSheet("font: bold 20pt Arial") - - - - after_deposition_preparation = self.layout_funcs.add_depo_heading('Procedure') - after_deposition_preparation.setStyleSheet("font: italic bold 17pt Arial ") - after_deposition_preparation_text = self.layout_funcs.add_depo_text(XChemToolTips.after_deposition_step_one_text()) - - - -############################################### - -# deposition_html_heading = self.layout_funcs.add_depo_heading('HTML export') -# deposition_html_heading.setStyleSheet("font: 20pt Arial Bold") -# -# introduction_text = self.layout_funcs.add_depo_text(XChemToolTips.html_summary_introduction()) -# -# html_export_button = QtGui.QPushButton('Export to HTML') -# html_export_button.clicked.connect(xce_object.export_to_html) -# html_export_button.setMaximumWidth(200) - - - - deposition_widget_list = [deposition_page_heading, - QtGui.QLabel(' \n '), - deposition_page_introduction,deposition_page_introduction_link, - QtGui.QLabel(' \n '), - - deposition_bound_state_heading, QtGui.QLabel(' \n '), - deposition_bound_state_prerequisites, - deposition_bound_state_prerequisites_text, QtGui.QLabel(' \n '), - deposition_bound_state_preparation, - deposition_bound_state_preparation_step_one_text, - xce_object.deposition_bounnd_state_preparation_ignore_event_map, - prepare_mmcif_button, - deposition_bound_state_preparation_step_two_text, - copy_mmcif_button, - pdb_group_deposition_instruction_one, - pdb_group_deposition_link, - pdb_group_deposition_instruction_two_two, - - QtGui.QLabel(' \n\n\n '), - - after_deposition_heading, QtGui.QLabel(' \n '), - after_deposition_preparation, - after_deposition_preparation_text, - - QtGui.QLabel(' \n\n\n '), - - deposition_ground_state_heading, QtGui.QLabel(' \n '), - deposition_ground_state_prerequisites, - deposition_ground_state_prerequisites_text, QtGui.QLabel(' \n '), - deposition_ground_state_preparation, - deposition_ground_state_preparation_step_one_text, - ground_state_pdb_button, xce_object.ground_state_pdb_button_label, - deposition_ground_state_log_info, - deposition_ground_state_preparation_step_two_text, - ground_state_mtz_button,xce_object.ground_state_mtz_button_label, - deposition_ground_state_preparation_step_three_text, - xce_object.ground_state_pandda_directory_label, - deposition_ground_state_preparation_step_four_text, - add_ground_state_db_button, - deposition_ground_state_preparation_step_five_text, - deposition_ground_state_preparation_step_six_text, - prepare_ground_state_mmcif_button, - deposition_ground_state_preparation_step_seven_text, - copy_apo_mmcif_button, - deposition_ground_state_preparation_step_eight_text, - pdb_group_deposition_link_two, - pdb_group_deposition_instruction_two, - - QtGui.QLabel(' \n\n\n ') - -# after_deposition_heading, QtGui.QLabel(' \n '), -# after_deposition_preparation, -# after_deposition_preparation_text - - ] - -# QtGui.QLabel(' \n\n\n '), -# -# deposition_html_heading, QtGui.QLabel(' \n '), -# introduction_text, -# html_export_button, QtGui.QLabel(' \n\n '), -#s QtGui.QLabel(' \n ')] -# -# deposition_widget_list2 = [update_html_button, QtGui.QLabel(' '), -# upload_html_heading, upload_html_text, QtGui.QLabel(' ')] - - self.layout_funcs.add_to_box(scrollLayout, deposition_widget_list) -# scrollLayout.addLayout(hbox_zenodo_upload_id) -# self.layout_funcs.add_to_box(scrollLayout, deposition_widget_list2) - - # container settings - scrollLayout.addStretch(1) - scroll.setWidget(scrollContent) - diff --git a/gui_scripts/layout.py b/gui_scripts/layout.py deleted file mode 100755 index 9eccbbff..00000000 --- a/gui_scripts/layout.py +++ /dev/null @@ -1,521 +0,0 @@ -import multiprocessing -import subprocess -import sys, os -from PyQt4 import QtGui, QtCore, QtWebKit -from functools import partial - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'lib')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'web')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) - -from settings_preferences import setup - -import XChemToolTips -import XChemMain - -import matplotlib.pyplot as plt -from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas - -from overview_tab import OverviewTab -from datasets_tab import DatasetsTab -from maps_tab import MapsTab -from pandda_tab import PanddaTab -from refinement_tab import RefinementTab -from deposition_tab import DepositionTab -from settings_tab import SettingsTab - - -class LayoutObjects(): - def __init__(self, xce_object): - self.layout_funcs = LayoutFuncs() - - # function to initialise the top menu bar - def initialise_menu_bar(self, xce_object): - ################################################################################################################ - # # - # MENU BAR - TOP OF GUI # - # # - ################################################################################################################ - - # initiate menu widget - menu_bar = QtGui.QMenuBar() - - # import menu bar dictionary - setup().top_menu_dict(xce_object) - - # create menu from menu dictionary - menu_bar = self.layout_funcs.setup_menubar(xce_object, menu_bar, xce_object.menu_dict) - - # END OF MENU BAR - CODE BELOW: stuff removed from apo structure stuff that appears might have a funky - # consequence - work out later. - - # xce_object.prepare_mmcif_files_dict = {} - # xce_object.prepare_mmcif_files_dict['apo'] = prepare_mmcif_files_for_apo_structures - # xce_object.prepare_mmcif_files_dict['ligand_bound'] = prepare_mmcif_files_for_ligand_bound_structures - - - return menu_bar - - # function containing setup for bottom boxes - def initialise_bottom_boxes(self, xce_object): - - icons_directory = os.path.join((os.getenv('XChemExplorer_DIR')), 'icons') - - # import all buttons - setup().bottom_box_buttons(xce_object) - - # setup datasource button - update_from_datasource_button = self.layout_funcs.setup_push_button(xce_object, - xce_object.datasource_button_dict) - - ################################################################################################################ - # # - # DATASETS BOX # - # # - ################################################################################################################ - - # setup the run button with push button function - xce_object.dataset_task_run_button = self.layout_funcs.setup_push_button(xce_object, - xce_object.dataset_task_run_button_dict) - - # setup the task button with push button function - xce_object.dataset_task_status_button = self.layout_funcs.setup_push_button(xce_object, - xce_object.dataset_task_status_button_dict) - - # array of both button xce_objects to apply to bottom box layout - dataset_buttons = [xce_object.dataset_task_run_button, xce_object.dataset_task_status_button] - - - # label for the bottom box layout - dataset_label = str(" Datasets") - - # return the frame and combobox from the bottom box setup function - frame_dataset_task, xce_object.dataset_tasks_combobox = self.layout_funcs.bottom_box_setup(xce_object, - dataset_label, - xce_object.dataset_tasks, - 'XChemToolTips.' - 'dataset_task_tip()', - dataset_buttons, - 'background: ' - 'rgb(240, 255, 140);') - - # define the combobox and buttons in dictionary key to determine behaviour - xce_object.workflow_widget_dict['Datasets'] = [xce_object.dataset_tasks_combobox, - xce_object.dataset_task_run_button, - xce_object.dataset_task_status_button] - - ################################################################################################################ - # # - # MAPS & RESTRAINTS BOX # - # # - ################################################################################################################ - # settings for the run button - - # setup the run button with push button function - xce_object.map_cif_file_task_run_button = \ - self.layout_funcs.setup_push_button(xce_object, - xce_object.map_cif_file_task_run_button_dict) - - # setup the task button with push button function - xce_object.map_cif_file_task_status_button = \ - self.layout_funcs.setup_push_button(xce_object, - xce_object.map_cif_file_task_status_button_dict) - - # array of both button xce_objects to apply to bottom box layout - map_cif_file_buttons = [xce_object.map_cif_file_task_run_button, xce_object.map_cif_file_task_status_button] - - # label for the bottom box layout - map_cif_file_label = str(" Maps & Restraints") - - # return the frame and combobox from the bottom box setup function - frame_map_cif_file_task, xce_object.map_cif_file_tasks_combobox = \ - self.layout_funcs.bottom_box_setup(xce_object, - map_cif_file_label, - xce_object.map_cif_file_tasks, - 'XChemToolTips.map_cif_file_' - 'task_tip()', - map_cif_file_buttons, - 'background: rgb(140, 255, ' - '150); ') - - # define the combobox and buttons in dictionary key to determine behaviour - xce_object.workflow_widget_dict['Maps'] = [xce_object.map_cif_file_tasks_combobox, - xce_object.map_cif_file_task_run_button, - xce_object.map_cif_file_task_status_button] - - ################################################################################################################ - # # - # HIT IDENTIFICATION BOX # - # # - ################################################################################################################ - # settings for the run button - - # setup the run button with push button function - xce_object.panddas_file_task_run_button = \ - self.layout_funcs.setup_push_button(xce_object, - xce_object.panddas_file_task_run_button_dict) - - # setup the task button with push button function - xce_object.panddas_file_task_status_button = \ - self.layout_funcs.setup_push_button(xce_object, - xce_object.panddas_file_task_status_button_dict) - - # array of both button xce_objects to apply to bottom box layout - panddas_file_buttons = [xce_object.panddas_file_task_run_button, xce_object.panddas_file_task_status_button] - - # label for the bottom box layout - panddas_file_label = str(" Hit Identification") - - # return the frame and combobox from the bottom box setup function - frame_panddas_file_task, xce_object.panddas_file_tasks_combobox = \ - self.layout_funcs.bottom_box_setup(xce_object, - panddas_file_label, - xce_object.panddas_file_tasks, - 'XChemToolTips.panddas_file_' - 'task_tip()', - panddas_file_buttons, - 'background: rgb(140,200,255)' - '; ') - - # define the combobox and buttons in dictionary key to determine behaviour - xce_object.workflow_widget_dict['PANDDAs'] = [xce_object.panddas_file_tasks_combobox, - xce_object.panddas_file_task_run_button, - xce_object.panddas_file_task_status_button] - - ################################################################################################################ - # # - # REFINEMENT BOX # - # # - ################################################################################################################ - # settings for the run button - - # setup the run button with push button function - xce_object.refine_file_task_run_button = \ - self.layout_funcs.setup_push_button(xce_object, xce_object.refine_file_task_run_button_dict) - - # setup the task button with push button function - xce_object.refine_file_task_status_button = \ - self.layout_funcs.setup_push_button(xce_object, xce_object.refine_file_task_status_button_dict) - - # array of both button xce_objects to apply to bottom box layout - refine_file_buttons = [xce_object.refine_file_task_run_button, xce_object.refine_file_task_status_button] - - # label for the bottom box layout - refine_file_label = str(" Refinement") - - # return the frame and combobox from the bottom box setup function - frame_refine_file_task, xce_object.refine_file_tasks_combobox = \ - self.layout_funcs.bottom_box_setup(xce_object, - refine_file_label, - xce_object.refine_file_tasks, - 'XChemToolTips.refine_file_task' - '_tip()', - refine_file_buttons, - 'background: rgb(245, 190, 255)' - ';') - - # define the combobox and buttons in dictionary key to determine behaviour - xce_object.workflow_widget_dict['Refinement'] = [xce_object.refine_file_tasks_combobox, - xce_object.refine_file_task_run_button, - xce_object.refine_file_task_status_button] - - return update_from_datasource_button, frame_dataset_task, frame_map_cif_file_task, frame_panddas_file_task, \ - frame_refine_file_task - - def main_layout(self, xce_object): - # initialise menu bar - menu_bar = self.initialise_menu_bar(xce_object) - - # initialise bottom boxes - update_from_datasource_button, frame_dataset_task, frame_map_cif_file_task, frame_panddas_file_task, \ - frame_refine_file_task = self.initialise_bottom_boxes(xce_object) - - # Tab layout & content - # -------------------- - # - # Overview - # |- datasource - TABLE - # |- summary - GRAPH - # - # Datasets - # |- summary - TABLE - # |- reprocess - TABLE - # - # Maps - TABLE - # - # PANDDAS - # |- pandda.analyse - TABLE - # |- Dataset Summary ------------------ - # |- Processing Output | HTML - # |- pandda.inspect | - # |- Statistical Map Summaries -------- - # - # Refinement - TABLE - # - # Deposition - # - # Settings - - # Setup tabs - OverviewTab().setup(xce_object) - DatasetsTab().setup(xce_object) - MapsTab().setup(xce_object) - PanddaTab().setup(xce_object) - RefinementTab().setup(xce_object) - DepositionTab().setup(xce_object) - SettingsTab().setup(xce_object) - - ################################################################################################################ - # # - # STATUS BAR # - # # - ################################################################################################################ - xce_object.status_bar = QtGui.QStatusBar() - xce_object.progress_bar = QtGui.QProgressBar() - xce_object.progress_bar.setMaximum(100) - xce_object.status_bar.setMaximumWidth(xce_object.screen.width()) - xce_object.progress_bar.setMaximumWidth(xce_object.screen.width()) - hbox_status = QtGui.QHBoxLayout() - hbox_status.addWidget(xce_object.status_bar) - hbox_status.addWidget(xce_object.progress_bar) - - vbox_main = QtGui.QVBoxLayout() - menu_bar.setMaximumWidth(xce_object.screen.width()) - vbox_main.addWidget(menu_bar) - xce_object.main_tab_widget.setMaximumSize(xce_object.screen.width(), xce_object.screen.height() - 245) - vbox_main.addWidget(xce_object.main_tab_widget) - - hboxTaskFrames = QtGui.QHBoxLayout() - - hboxTaskFrames.addWidget(update_from_datasource_button) - hboxTaskFrames.addWidget(frame_dataset_task) - hboxTaskFrames.addWidget(frame_map_cif_file_task) - hboxTaskFrames.addWidget(frame_panddas_file_task) - hboxTaskFrames.addWidget(frame_refine_file_task) - - vbox_main.addLayout(hboxTaskFrames) - - vbox_main.addLayout(hbox_status) - - xce_object.window.setLayout(vbox_main) - - xce_object.status_bar.showMessage('Ready') - xce_object.window.show() - - if xce_object.data_source_file != '': - write_enabled = xce_object.check_write_permissions_of_data_source() - if not write_enabled: - xce_object.data_source_set = False - - def workflow(self, xce_object): - ################################################################################################################ - # # - # ========================================== WORKFLOW TASK CONTAINER ========================================= # - # # - ################################################################################################################ - - - # workflow task container - order of tabs as they appear for the main window - xce_object.workflow = ['Overview', # 0 - 'Datasets', # 1 - 'Maps', # 2 - 'PANDDAs', # 3 - 'Refinement', # 4 - 'Deposition', # 6 - 'Settings'] # 5 - - # dictionary with keys corresponding to each stage in the workflow - xce_object.workflow_dict = {xce_object.workflow[0]: 'Overview', - xce_object.workflow[1]: 'Datasets', - xce_object.workflow[2]: 'Maps', - xce_object.workflow[3]: 'PANDDAs', - xce_object.workflow[4]: 'Refinement', - xce_object.workflow[6]: 'Settings', - xce_object.workflow[5]: 'Deposition'} - - xce_object.workflow_widget_dict = {} - - # tab widget - xce_object.main_tab_widget = QtGui.QTabWidget() - xce_object.tab_dict = {} - self.layout_funcs.make_tab_dict(xce_object.workflow, xce_object.main_tab_widget, xce_object.tab_dict) - - -class LayoutFuncs(): - def __init__(self): - pass - - def make_tab_dict(self, tab_list, tab_widget, tab_dict): - for page in tab_list: - tab = QtGui.QWidget() - vbox = QtGui.QVBoxLayout(tab) - tab_widget.addTab(tab, page) - tab_dict[page] = [tab, vbox] - - def add_checkbox(self, xce_object, checkbox, function, checkopt=False): - checkbox.toggle() - checkbox.setChecked(checkopt) - eval(str('checkbox.stateChanged.connect(' + function + ')')) - - def table_setup(self, table, table_columns, sortingopt=True): - table.setColumnCount(len(table_columns)) - table.setSortingEnabled(sortingopt) - table.setHorizontalHeaderLabels(table_columns) - table.resizeRowsToContents() - table.resizeColumnsToContents() - - def pandda_html(self, xce_object): - if os.path.exists(str(xce_object.panddas_directory + '/interesting_datasets')): - print('WARNING: USING RESULTS FROM OLD PANDDA ANALYSE! THIS IS NOT FULLY SUPPORTED IN XCE2') - print('PLEASE CHANGE YOUR PANDDA DIRECTORY TO A NEW RUN, OR USE THE OLD VERSION OF XCE!') - xce_object.pandda_initial_html_file = str( - xce_object.panddas_directory + '/results_summareis/pandda_initial.html') - xce_object.pandda_analyse_html_file = str( - xce_object.panddas_directory + '/results_summaries/pandda_analyse.html') - xce_object.pandda_initial_html_file = str( - xce_object.panddas_directory + '/analyses/html_summaries/' + 'pandda_initial.html') - xce_object.pandda_analyse_html_file = str( - xce_object.panddas_directory + '/analyses/html_summaries/' + 'pandda_analyse.html') - xce_object.pandda_inspect_html_file = str( - xce_object.panddas_directory + '/analyses/html_summaries/' + 'pandda_inspect.html') - - # function for datasource, run and status button setup - def setup_push_button(self, xce_object, button_dict): - # use iterkeys to determine order of key by letter - for name in sorted(button_dict.iterkeys()): - # add current item to menu bar - button = eval('QtGui.QPushButton("' + str(button_dict[name][0]) + '")') - # for each configuration item - for button_config in button_dict[name][1]: - eval(str('button.setToolTip(' + str(button_config[0]) + ')')) - eval(str('button.setStyleSheet("' + str(button_config[1] + '")'))) - if len(button_config[2]) > 1: - eval(str('button.setFont(' + str(button_config[2]) + ')')) - eval(str('button.clicked.connect(' + str(button_config[3]) + ')')) - - return button - - # function to setup one of the bottom boxes - def bottom_box_setup(self, xce_object, label, dropdown_options, dropdown_tooltip, buttons, colour): - - frame = QtGui.QFrame() - frame.setFrameShape(QtGui.QFrame.StyledPanel) - frame.setStyleSheet("QFrame { " - "border-radius: 1px; padding: 0px; margin: 0px; background-color: rgb(255, 255, 255); }") - - vbox = QtGui.QVBoxLayout() - label = QtGui.QLabel(label) - label.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter) - # label.setFont(xce_object.headlineLabelfont) - label.setStyleSheet(str(" QLabel { border: 1px solid rgb(184, 192, 210); border-radius: 1px;" + str(colour) + - "padding: 3px; margin: 0px; font: bold 14pt}")) - vbox.addWidget(label) - - hboxAction = QtGui.QHBoxLayout() - combobox = QtGui.QComboBox() - for task in dropdown_options: - combobox.addItem(task) - eval('combobox.setToolTip(' + str(dropdown_tooltip) + ')') - combobox.setStyleSheet(" QComboBox { padding: 1px; margin: 1px }") - hboxAction.addWidget(combobox) - - vboxButton = QtGui.QVBoxLayout() - for button in buttons: - vboxButton.addWidget(button) - hboxAction.addLayout(vboxButton) - vbox.addLayout(hboxAction) - vbox.setSpacing(0) - vbox.setMargin(0) - frame.setLayout(vbox) - frame.setMaximumWidth((xce_object.screen.width() - 20) / 5) - - return frame, combobox - - # function to add items to top menu bar - def setup_menubar(self, xce_object, menu_bar, menu_items_dict): - # use iterkeys to determine order of key by letter - for config in sorted(menu_items_dict.iterkeys()): - # add current item to menu bar - menu = eval('menu_bar.addMenu("' + str(menu_items_dict[config][0]) + '")') - # for each configuration item - for menu_item in menu_items_dict[config][1]: - # add the drop down option - action = eval(str('QtGui.QAction("' + str(menu_item[0]) + '", xce_object.window)')) - # add a shortcut if defined - if len(menu_item[1]) > 1: - eval(str('action.setShortcut("' + str(menu_item[1]) + '")')) - # connect the relevant function and add as an action - try: - action.triggered.connect(menu_item[2]) - menu.addAction(action) - except: - print(menu_item[2]) - raise - - return menu_bar - - def add_to_box(self, frame, widgets_list): - for widget in widgets_list: - frame.addWidget(widget) - - def populate_combobox(self, combobox_list, combobox): - for item in combobox_list: - combobox.addItem(item) - - def add_depo_heading(self, heading_text): - heading = QtGui.QLabel(str(heading_text)) - heading.setStyleSheet("font: bold 20pt Arial") - - return heading - - def add_depo_text(self, text): - out_text = QtGui.QLabel(text) - out_text.setStyleSheet("font: 17pt Arial") - - return out_text - - def settings_section_setup(self, vbox, label_text, directory, button_text, button_function): - vbox.addWidget(QtGui.QLabel(label_text)) - - hbox = QtGui.QHBoxLayout() - directory_label = QtGui.QLabel(directory) - hbox.addWidget(directory_label) - button = QtGui.QPushButton(button_text) - button.setMaximumWidth(500) - button.clicked.connect(button_function) - hbox.addWidget(button) - - vbox.addLayout(hbox) - vbox.addWidget(QtGui.QLabel(' ')) - vbox.addWidget(QtGui.QLabel(' ')) - - return directory_label - - def add_widgets_layouts(self, xce_object): - tab_add_widget = [ - [xce_object.tab_dict[xce_object.workflow_dict['Overview']][1], xce_object.overview_tab_widget], - [xce_object.overview_tab_dict['Data Source'][1], xce_object.overview_datasource_table], - [xce_object.overview_tab_dict['Summary'][1], xce_object.overview_canvas], - [xce_object.pandda_tab_dict['Dataset Summary'][1], xce_object.pandda_initial_html], - [xce_object.pandda_tab_dict['Processing Output'][1], xce_object.pandda_analyse_html], - [xce_object.pandda_tab_dict['pandda.inspect'][1], xce_object.pandda_inspect_html]] - - tab_add_layout = [ - [xce_object.tab_dict[xce_object.workflow_dict['Datasets']][1], xce_object.datasets_data_collection_vbox], - [xce_object.datasets_tab_dict['Summary'][1], xce_object.datasets_summarys_vbox_for_table], - [xce_object.datasets_tab_dict['Summary'][1], xce_object.datasets_summarys_vbox_for_details], - [xce_object.datasets_tab_dict['Reprocess'][1], xce_object.reprocess_vbox], - [xce_object.tab_dict[xce_object.workflow_dict['Maps']][1], xce_object.maps_checkbutton_hbox], - [xce_object.tab_dict[xce_object.workflow_dict['Maps']][1], xce_object.initial_model_vbox_for_table], - [xce_object.pandda_tab_dict['Statistical Map Summaries'][1], xce_object.pandda_map_layout], - [xce_object.pandda_tab_dict['pandda.analyse'][1], xce_object.pandda_analyse_hbox], - [xce_object.tab_dict[xce_object.workflow_dict['PANDDAs']][1], xce_object.panddas_results_vbox], - [xce_object.tab_dict[xce_object.workflow_dict['Refinement']][1], xce_object.summary_vbox_for_table], - [xce_object.tab_dict[xce_object.workflow_dict['Deposition']][1], xce_object.deposition_vbox], - [xce_object.tab_dict[xce_object.workflow_dict['Settings']][1], xce_object.settings_vbox]] - - for item in tab_add_widget: - item[0].addWidget(item[1]) - - for item in tab_add_layout: - item[0].addLayout(item[1]) diff --git a/gui_scripts/maps_tab.py b/gui_scripts/maps_tab.py deleted file mode 100755 index b0bdba2a..00000000 --- a/gui_scripts/maps_tab.py +++ /dev/null @@ -1,58 +0,0 @@ -import sys, os -from PyQt4 import QtGui, QtCore, QtWebKit - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) - -import layout - - -class MapsTab(): - def __init__(self): - self.layout_funcs = layout.LayoutFuncs() - - def setup(self, xce_object): - ################################################################################################################ - # # - # MAPS TAB # - # # - ################################################################################################################ - # select box for dimple - xce_object.select_sample_for_dimple_box = QtGui.QCheckBox('(de-)select all samples for DIMPLE') - self.layout_funcs.add_checkbox(xce_object, xce_object.select_sample_for_dimple_box, - 'xce_object.set_run_dimple_flag') - - # set new reference button - set_new_reference_button = QtGui.QPushButton("Set New Reference (if applicable)") - set_new_reference_button.clicked.connect(xce_object.set_new_reference_if_applicable) - - # refresh button - refresh_reference_file_list_button = QtGui.QPushButton("Refresh reference file list") - refresh_reference_file_list_button.clicked.connect(xce_object.refresh_reference_file_list) - - # list and populate reference files - xce_object.reference_file_list = xce_object.get_reference_file_list(' ') - xce_object.reference_file_selection_combobox = QtGui.QComboBox() - xce_object.populate_reference_combobox(xce_object.reference_file_selection_combobox) - - # setup hbox to hold everything and add widgets - xce_object.maps_checkbutton_hbox = QtGui.QHBoxLayout() - maps_checkbutton_widgets = [xce_object.select_sample_for_dimple_box, set_new_reference_button, - refresh_reference_file_list_button, xce_object.reference_file_selection_combobox] - - self.layout_funcs.add_to_box(xce_object.maps_checkbutton_hbox, maps_checkbutton_widgets) - - # table setup - xce_object.maps_table = QtGui.QTableWidget() - self.layout_funcs.table_setup(xce_object.maps_table, xce_object.maps_table_columns) - - # box for table, add to box, add to tab - xce_object.initial_model_vbox_for_table = QtGui.QVBoxLayout() - xce_object.initial_model_vbox_for_table.addWidget(xce_object.maps_table) - - # create context menu... no idea where this lives again. - xce_object.popMenu_for_maps_table = QtGui.QMenu() - run_dimple = QtGui.QAction("mark selected for dimple run", xce_object.window) - run_dimple.triggered.connect(xce_object.select_sample_for_dimple) - xce_object.popMenu_for_maps_table.addAction(run_dimple) - xce_object.maps_table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - xce_object.maps_table.customContextMenuRequested.connect(xce_object.on_context_menu_initial_model) diff --git a/gui_scripts/refinement_tab.py b/gui_scripts/refinement_tab.py deleted file mode 100755 index 71b50a5b..00000000 --- a/gui_scripts/refinement_tab.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys, os -from PyQt4 import QtGui, QtCore, QtWebKit - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) - -import layout - - -class RefinementTab(): - def __init__(self): - self.layout_funcs = layout.LayoutFuncs() - - def setup(self, xce_object): - ################################################################################################################ - # # - # REFINEMENT TAB # - # # - ################################################################################################################ - xce_object.summary_vbox_for_table = QtGui.QVBoxLayout() - - # table - xce_object.refinement_table = QtGui.QTableWidget() - self.layout_funcs.table_setup(xce_object.refinement_table, xce_object.refinement_table_columns) - xce_object.summary_vbox_for_table.addWidget(xce_object.refinement_table) - diff --git a/gui_scripts/settings_preferences.py b/gui_scripts/settings_preferences.py deleted file mode 100755 index 15a39ce7..00000000 --- a/gui_scripts/settings_preferences.py +++ /dev/null @@ -1,630 +0,0 @@ -import os, sys, subprocess -from PyQt4 import QtCore, QtGui -from functools import partial -import webbrowser - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'lib')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'web')) - -import XChemUtils -import XChemDB -import XChemMain -import XChemLog -import XChemDeposit - - -class setup(): - def __init__(self): - pass - - def openFile(self, file): - if sys.platform == 'linux2': - subprocess.call(["xdg-open", file]) - else: - os.startfile(file) - - def set_xce_logfile(self, xce_object): - XChemLog.startLog(xce_object.xce_logfile).create_logfile(xce_object.xce_version) - xce_object.update_log = XChemLog.updateLog(xce_object.xce_logfile) - - def settings(self, xce_object): - # set XCE version - xce_object.xce_version = 'v1.4.0' - - # general settings - xce_object.allowed_unitcell_difference_percent = 12 - xce_object.acceptable_low_resolution_limit_for_data = 3.5 - xce_object.filename_root = '${samplename}' - xce_object.data_source_set = False - xce_object.max_queue_jobs = 100 - - ## directory settings - - # set current directory and direct log to it - xce_object.current_directory = os.getcwd() - xce_object.xce_logfile = os.path.join(xce_object.current_directory, 'xce.log') - - # if in the correct place, set the various directories - if 'labxchem' in xce_object.current_directory: - if len(xce_object.current_directory.split('/')) >= 9 and xce_object.current_directory.split('/')[6] == 'processing' and xce_object.current_directory.split('/')[8] == 'processing': - xce_object.labxchem_directory = '/' + os.path.join( - *xce_object.current_directory.split('/')[1:8]) # need splat operator: * - xce_object.labxchem_directory_current = '/' + os.path.join( - *xce_object.current_directory.split('/')[1:9]) # labxchem_directory_current is where they actually have write permission - else: - xce_object.labxchem_directory = '/' + os.path.join( - *xce_object.current_directory.split('/')[1:6]) # need splat operator: * - xce_object.labxchem_directory_current = '/' + os.path.join( - *xce_object.current_directory.split('/')[1:7]) # need splat operator: * -# xce_object.labxchem_directory = '/' + os.path.join( -# *xce_object.current_directory.split('/')[1:6]) # need splat operator: * - xce_object.beamline_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'beamline') - if os.path.isdir(os.path.join(xce_object.labxchem_directory, 'processing', 'analysis','model_building')): - xce_object.initial_model_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'analysis', - 'model_building') - else: - xce_object.initial_model_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'analysis', - 'initial_model') - xce_object.reference_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'reference') - xce_object.database_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'database') - xce_object.panddas_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'analysis', - 'panddas') - xce_object.datasets_summary_file = os.path.join(xce_object.database_directory, - str(os.getcwd().split('/')[5]) + '_summary.pkl') - xce_object.data_source_file = '' - xce_object.html_export_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'html') - xce_object.group_deposit_directory = os.path.join(xce_object.labxchem_directory, 'processing', - 'group_deposition') - if os.path.isfile( - os.path.join(xce_object.labxchem_directory, 'processing', 'database', 'soakDBDataFile.sqlite')): - xce_object.data_source_file = 'soakDBDataFile.sqlite' - xce_object.database_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'database') - xce_object.data_source_set = True - xce_object.db = XChemDB.data_source( - os.path.join(xce_object.database_directory, xce_object.data_source_file)) - xce_object.db.create_missing_columns() - - xce_object.ccp4_scratch_directory = os.path.join(xce_object.labxchem_directory, 'processing', 'tmp') - - directory_list = [xce_object.beamline_directory, os.path.join(xce_object.labxchem_directory, - 'processing', 'analysis'), - xce_object.initial_model_directory, xce_object.panddas_directory, - xce_object.reference_directory, - xce_object.database_directory, xce_object.ccp4_scratch_directory, - xce_object.html_export_directory, - xce_object.group_deposit_directory] - - for directory in directory_list: - if not os.path.isdir(directory): - os.mkdir(directory) - - # otherwise, use the current working directory - else: - xce_object.labxchem_directory_current = xce_object.current_directory - xce_object.beamline_directory = xce_object.current_directory - xce_object.initial_model_directory = xce_object.current_directory - xce_object.reference_directory = xce_object.current_directory - xce_object.database_directory = xce_object.current_directory - xce_object.data_source_file = '' - xce_object.ccp4_scratch_directory = os.getenv('CCP4_SCR') - xce_object.panddas_directory = xce_object.current_directory - xce_object.datasets_summary_file = '' - xce_object.group_deposit_directory = xce_object.current_directory - - - ## deposition - - xce_object.deposit_dict = {} - - ## internal lists and dictionaries - - xce_object.data_collection_list = [] - xce_object.visit_list = [] - xce_object.target = '' - xce_object.dataset_outcome_combobox_dict = {} - xce_object.data_collection_dict = {} - xce_object.xtal_db_dict = {} - xce_object.pandda_analyse_input_table_dict = {} - xce_object.dewar_configuration_dict = {} - xce_object.data_collection_statistics_dict = {} - xce_object.initial_model_dimple_dict = {} # contains toggle button if dimple should be run - xce_object.reference_file_list = [] - xce_object.all_columns_in_data_source = XChemDB.data_source(os.path.join - (xce_object.database_directory, - xce_object.data_source_file)) \ - .return_column_list() - xce_object.albula_button_dict = {} # using dials.image_viewer instead of albula, but keep name for dictionary - xce_object.xtalform_dict = {} - - xce_object.dataset_outcome_dict = {} # contains the dataset outcome buttons - xce_object.data_collection_table_dict = {} # contains the dataset table - xce_object.data_collection_image_dict = {} - xce_object.data_collection_column_three_dict = {} - xce_object.datasets_summary_dict = {} - xce_object.diffraction_data_table_dict = {} - xce_object.refinement_table_dict = {} - xce_object.main_data_collection_table_exists = False - xce_object.timer_to_check_for_new_data_collection = QtCore.QTimer() - - xce_object.agamemnon = False - xce_object.target_list, xce_object.visit_list = XChemMain.get_target_and_visit_list( - xce_object.beamline_directory,False) - - xce_object.diffraction_data_dict = {} - - ## internal switches and flags - - xce_object.explorer_active = 0 - xce_object.coot_running = 0 - xce_object.progress_bar_start = 0 - xce_object.progress_bar_step = 0 - xce_object.albula = None - xce_object.albula_subframes = [] - xce_object.show_diffraction_image = None - xce_object.gdaLogInstructions = [0,False] - # can be any widget to be displayed in data collection summary tab - xce_object.data_collection_details_currently_on_display = None - - xce_object.dataset_outcome = ["success", - "Failed - centring failed", - "Failed - no diffraction", - "Failed - processing", - "Failed - loop empty", - "Failed - loop broken", - "Failed - low resolution", - "Failed - no X-rays", - "Failed - unknown"] - - xce_object.refinement_stage = ['0 - All Datasets', - '1 - Analysis Pending', - '2 - PANDDA model', - '3 - In Refinement', - '4 - CompChem ready', - '5 - Deposition ready', - '6 - Deposited'] - - self.set_xce_logfile(xce_object) - - ## external software packages - xce_object.using_remote_qsub_submission = False - xce_object.remote_qsub_submission = "/usr/bin/ssh @nx.diamond.ac.uk 'module load global/cluster; qsub'" - - xce_object.update_log = XChemLog.updateLog(xce_object.xce_logfile) - xce_object.update_log.insert('new session started') - xce_object.diffraction_data_directory = xce_object.current_directory - xce_object.diffraction_data_search_info = 'n/a' - xce_object.diffraction_data_reference_mtz = 'ignore' - xce_object.html_export_directory = os.getcwd() - xce_object.external_software = XChemUtils.external_software(xce_object.xce_logfile).check() - - xce_object.second_cif_file = None - - software_list = ['acedrg', 'phenix.elbow', 'grade'] - - for software in software_list: - if xce_object.external_software[software]: - xce_object.restraints_program = str(software) - xce_object.update_log.insert('will use ' + str(software) + ' for generation of ligand coordinates and' - ' restraints') - else: - xce_object.restraints_program = '' - xce_object.update_log.insert( - 'No program for generation of ligand coordinates and restraints available!') - - def preferences(self, xce_object): - ## preferences - - xce_object.preferences_data_to_copy = [['aimless logiles and merged mtz only', 'mtz_log_only'], ] - # ['All Files in the respective auto-processing directory','everything'], - - xce_object.preferences_selection_mechanism = ['IsigI*Comp*UniqueRefl', - 'highest_resolution', - 'lowest_Rfree', - 'dials - only', - 'xia2 3d - only', - 'xia2 3dii - only', - 'autoProc - only', - 'autoProc_staraniso - only'] - - xce_object.allowed_unitcell_difference_percent = 12 - xce_object.acceptable_low_resolution_limit_for_data = 3.5 - xce_object.filename_root = '${samplename}' - xce_object.max_queue_jobs = 100 - xce_object.dimple_twin_mode = False - - - xce_object.preferences_initial_refinement_pipeline = [ 'dimple', - 'pipedream', - 'phenix.ligand_pipeline' ] - - xce_object.preferences = {'processed_data_to_copy': 'mtz_log_only', - 'dataset_selection_mechanism': 'IsigI*Comp*UniqueRefl', - 'allowed_unitcell_difference_percent': 12, - 'acceptable_low_resolution_limit_for_data': 3.5, - 'acceptable_low_resolution_Rmerge': 0.1, - 'filename_root': '${samplename}', - 'max_queue_jobs': 100, - 'dimple_twin_mode': False, - 'initial_refinement_pipeline': 'dimple' } - - - ## settings - - xce_object.settings = {'current_directory': xce_object.current_directory, - 'beamline_directory': xce_object.beamline_directory, - 'datasets_summary': xce_object.datasets_summary_file, - 'initial_model_directory': xce_object.initial_model_directory, - 'panddas_directory': xce_object.panddas_directory, - 'reference_directory': xce_object.reference_directory, - 'database_directory': xce_object.database_directory, - 'data_source': os.path.join(xce_object.database_directory, xce_object.data_source_file), - 'ccp4_scratch': xce_object.ccp4_scratch_directory, - 'unitcell_difference': xce_object.allowed_unitcell_difference_percent, - 'too_low_resolution_data': xce_object.acceptable_low_resolution_limit_for_data, - 'filename_root': xce_object.filename_root, - 'preferences': xce_object.preferences, - 'xce_logfile': xce_object.xce_logfile, - 'max_queue_jobs': xce_object.max_queue_jobs, - 'diffraction_data_directory': xce_object.diffraction_data_directory, - 'html_export_directory': xce_object.html_export_directory, - 'group_deposit_directory': xce_object.group_deposit_directory, - 'remote_qsub': '', - 'dimple_twin_mode': False, - 'agamemnon': False } - - def tables(self, xce_object): - # Table column settings - - # functions that use tables.overview_datasource_table_columns: - # - # - select_datasource_columns_to_display() - dropdown in datasource top menu (select columns to show) - # - populate_data_source_table() - appears to be completely unused, so commented out - # - populate_and_update_datasource_table() - used within select_datasource_columns_to_display and - # update_all_tables() - - xce_object.overview_datasource_table_columns = ['Sample ID', - 'Compound ID', - 'Smiles', - 'Visit', - 'Resolution\n[Mn = 1.5]', - 'Refinement\nRfree', - 'Data Collection\nDate', - 'Puck', - 'PuckPosition', - 'Ligand\nConfidence'] - - # functions that use tables.datasets_summary_table_columns: - # - # - populate_datasets_summary_table() - appears in create_widgets_for_autoprocessing_results_only() - # - user_update_selected_autoproc_datasets_summary_table() - # - appears in create_widgets_for_autoprocessing_results_only() - - xce_object.datasets_summary_table_columns = ['Sample ID', - 'Resolution\n[Mn = 2.0]', - 'DataProcessing\nSpaceGroup', - 'DataProcessing\nRfree', - 'SoakDB\nBarcode', - 'GDA\nBarcode', - 'Rmerge\nLow', - 'auto-assigned', - 'DataCollection\nOutcome', - 'img1', - 'img2', - 'img3', - 'img4' -# 'img5', -# 'Show\nDetails', -# 'Show Diffraction\nImage' - ] - - # functions that use tables.data_collection_table_columns: - # - # - show_results_from_all_pipelines() - appears in populate_datasets_summary_table() - - xce_object.data_collection_table_columns = ['Sample ID', - 'Visit', - 'Run', - 'Program', - 'Resolution\nOverall', - 'Resolution\nHigh', - 'DataProcessing\nSpaceGroup', - 'Mn\nHigh', - 'Rmerge\nLow', - 'Completeness\nOverall', - 'DataProcessing\nUnitCell', - 'DataProcessing\nRfree' - 'DataProcessing\nScore'] - - - - # functions that use tables.datasets_reprocess_columns: - # - # - update_datasets_reprocess_table() - appears in search_for_datasets() - - xce_object.datasets_reprocess_columns = ['Dataset ID', - 'Sample ID', - 'Run\nxia2', - 'Resolution\n[Mn = 1.5]', - 'Rmerge\nLow', - 'Dimple\nRfree', - 'DataProcessing\nSpaceGroup', - 'DataProcessing\nUnitCell', - 'DataProcessing\nStatus'] - - # functions that use tables.maps_table_columns: - # - # - update_datasets_reprocess_table() - appears in create_maps_table() - - xce_object.maps_table_columns = ['Sample ID', - 'Select', - 'Compound ID', - 'Smiles', - 'Resolution\n[Mn = 1.5]', - 'Dimple\nRcryst', - 'Dimple\nRfree', - 'DataProcessing\nSpaceGroup', - 'Reference\nSpaceGroup', - 'Difference\nUC Volume (%)', - 'Reference File', - 'DataProcessing\nUnitCell', - 'Dimple\nStatus', - 'Compound\nStatus', - 'LastUpdated'] - - # functions that use tables.pandda_table_columns: - # - # - populate_pandda_analyse_input_table() - appears in update_all_tables() - - xce_object.pandda_table_columns = [ - 'Sample ID', - 'Refinement\nSpace Group', - 'Resolution\n[Mn = 1.5]', - 'Dimple\nRcryst', - 'Dimple\nRfree', - 'Crystal Form\nName', - 'Ignore\ncompletely', - 'Exclude from\n characterisation\n(binds)', - 'Exclude from\n z-map analysis\n(does not bind)'] - - # functions that use tables.refinement_table_columns: - # - # - populate_and_update_refinement_table() - appears in update_all_tables - - xce_object.refinement_table_columns = ['Sample ID', - 'Compound ID', - 'Refinement\nSpace Group', - 'Refinement\nResolution', - 'Refinement\nRcryst', - 'Refinement\nRfree', - 'Refinement\nOutcome', - 'PanDDA site details', - 'Refinement\nStatus'] - - def top_menu_dict(self, xce_object): - - # dictionary containing config for top menu setup - # menu dict = { 'order letter: menu_item_name': ["name_in_menu", - # [ - # ['text_in_menu', 'shortcut', 'trigger function']], - # [...], - # ]] - # } - xce_object.menu_dict = {'A: file': ["&File", - [ - ['Open Config File', 'Ctrl+O', xce_object.open_config_file], - ['Save Config File', 'Ctrl+S', xce_object.save_config_file], - ['Quit', 'Ctrl+Q', xce_object.quit_xce] - ]], - 'B: datasource': ["&Datasource", - [ - ['Reload Samples From Datasource', '', - xce_object.datasource_menu_reload_samples], - ['Save Samples to Datasource', '', - xce_object.datasource_menu_save_samples], - ['Import CSV file into Datasource', '', - xce_object.datasource_menu_import_csv_file], - ['Export CSV file from Datasource', '', - xce_object.datasource_menu_export_csv_file], - ['Update datasource from file system', '', - xce_object.datasource_menu_update_datasource], - ['Select columns to show', '', - xce_object.select_datasource_columns_to_display], - ['Create New Datasource (SQLite)', '', - xce_object.create_new_data_source], - ['Export CSV for wonka', '', xce_object.export_data_for_WONKA] - ]], - 'C: preferences': ["&Preferences", - [ - ['Edit preferences', '', xce_object.show_preferences] - ]], - 'D: deposition': ["&Deposition", - [ - ['Edit information', '', xce_object.deposition_data], - ['Export to HTML', '', xce_object.export_to_html], -# ['Find PanDDA apo structures', '', -# xce_object.create_missing_apo_records_in_depositTable], -# ['Update file info of apo structures', '', -# xce_object.update_file_information_of_apo_records], -# ['Prepare mmcif for apo structures', '', -# xce_object.prepare_models_for_deposition_apo], -# ['Prepare mmcif for ligand bound structures', '', -# xce_object.prepare_models_for_deposition_ligand_bound], -# ['Copy files to group deposition directory (ligand bound)', '', -# xce_object.prepare_for_group_deposition_upload_ligand_bound], -# ['Copy files to group deposition directory (ground state)', '', -# xce_object.prepare_for_group_deposition_upload_ground_state], - ['Update DB with PDB codes', '', xce_object.enter_pdb_codes], - ['Check SMILES', '', xce_object.check_smiles_in_db_and_pdb] - ]], - 'E: proasis': ["Proasis", - [ - ['Launch Proasis in browser', '', partial(webbrowser.open, - url='http://cs04r-sc-vserv-137.diamond.ac.uk/Proasis4_2017/')] - ]], - 'F: help': ["&Help", - [ - ['Open XCE manual', '', - lambda: setup().openFile( - "/dls/science/groups/i04-1/software/XCE_manual_2018-11-09.pdf" - ) - ], - ['Open XCE tutorial', '', - lambda: setup().openFile( - "/dls/science/groups/i04-1/software/docs/XChemExplorer.pdf")], - ['Troubleshooting', '', - lambda: setup().openFile( - "/dls/science/groups/i04-1/software/xce_troubleshooting.pdf")] - ]], - 'G: labels': ["&Labels", - [ - ['Edit label information', '', xce_object.add_label_information] - ]] - - } - - def bottom_box_buttons(self, xce_object): - self.dropdown_items(xce_object) - - xce_object.datasource_button_dict = {'datasource_button': [r"Update Tables\nFrom Datasource", - [ - [ - 'XChemToolTips.update_from_datasource_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px; ' - 'background: rgb(197,197,197) }', - # stylesheet - 'xce_object.headlineLabelfont', # font - 'xce_object.datasource_menu_reload_samples'] - # action - ]]} - - xce_object.dataset_task_run_button_dict = {'dataset_run_button': - [r"Run", - [ - ['XChemToolTips.dataset_task_run_button_tip()', # tooltip - 'QPushButton { padding: 1px; margin: 1px }', # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - xce_object.dataset_task_status_button_dict = {'dataset_status_button': - [r"Status", - [ - ['XChemToolTips.dataset_task_status_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px }', - # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - xce_object.map_cif_file_task_run_button_dict = {'dataset_run_button': - [r"Run", - [ - ['XChemToolTips.map_cif_file_task_run_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px }', - # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - xce_object.map_cif_file_task_status_button_dict = {'dataset_status_button': - [r"Status", - [ - [ - 'XChemToolTips.map_cif_file_task_status_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px }', - # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - xce_object.panddas_file_task_run_button_dict = {'dataset_run_button': - [r"Run", - [ - ['XChemToolTips.panddas_file_task_run_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px }', - # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - xce_object.panddas_file_task_status_button_dict = {'dataset_status_button': - [r"Status", - [ - [ - 'XChemToolTips.panddas_file_task_status_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px }', - # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - xce_object.refine_file_task_run_button_dict = {'dataset_run_button': - [r"Run", - [ - ['XChemToolTips.refine_file_task_run_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px }', - # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - xce_object.refine_file_task_status_button_dict = {'dataset_status_button': - [r"Status", - [ - [ - 'XChemToolTips.refine_file_task_status_button_tip()', - # tooltip - 'QPushButton { padding: 1px; margin: 1px }', - # stylesheet - '', # font - 'xce_object.button_clicked'] # action - ]]} - - def dropdown_items(self, xce_object): - xce_object.dataset_tasks = ['Get New Results from Autoprocessing', -# 'Run DIMPLE on All Autoprocessing MTZ files', - 'Rescore Datasets', - 'Run xia2 on selected datasets', - 'Run xia2 on selected datasets - overwrite'] - - xce_object.map_cif_file_tasks = ['Run initial refinement on selected MTZ files', - 'Remove selected initial refinement files', - 'Set only results from selected pipeline', -# 'Create CIF/PDB/PNG file of ALL compounds', -# 'Create CIF/PDB/PNG file of NEW compounds', - 'Create CIF/PDB/PNG file of SELECTED compounds', - 'Merge ligand CIF file with selected compounds', - 'Restore original CIF file of selected compounds', - 'Fit ligands into maps after initial refinement' - ] - - xce_object.panddas_file_tasks = ['pandda.analyse', - 'pandda.inspect', - 'run pandda.inspect at home', - 'Export NEW PANDDA models', - 'Export ALL PANDDA models', - 'Show HTML summary', -# 'Update datasource with results from pandda.inspect', - 'cluster datasets', - 'Event Map -> SF', - 'apo -> mmcif', - 'check modelled ligands', - 'pre-run for ground state model', - 'Build ground state model'] - - xce_object.refine_file_tasks = ['Open COOT', - 'Open COOT - test -'] - -# xce_object.refine_file_tasks = ['Open COOT', -# 'Open COOT for old PanDDA', -# 'Update Deposition Table', -# 'Prepare Group Deposition'] - diff --git a/gui_scripts/settings_tab.py b/gui_scripts/settings_tab.py deleted file mode 100755 index 2cf2e147..00000000 --- a/gui_scripts/settings_tab.py +++ /dev/null @@ -1,141 +0,0 @@ -import sys, os -from PyQt4 import QtGui, QtCore, QtWebKit - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) - -import layout - - -class SettingsTab(): - def __init__(self): - self.layout_funcs = layout.LayoutFuncs() - - def setup(self, xce_object): - ################################################################################################################ - # # - # SETTINGS TAB # - # # - ################################################################################################################ - xce_object.settings_container = QtGui.QWidget() - xce_object.buttons_etc = QtGui.QWidget() - xce_object.settings_vbox = QtGui.QVBoxLayout() - - xce_object.scroll = QtGui.QScrollArea(xce_object.settings_container) - xce_object.settings_vbox.addWidget(xce_object.scroll) - scrollContent_settings = QtGui.QWidget(xce_object.scroll) - - scrollLayout_settings = QtGui.QVBoxLayout(scrollContent_settings) - scrollContent_settings.setLayout(scrollLayout_settings) - - # Settings Tab - xce_object.data_collection_vbox_for_settings = QtGui.QVBoxLayout() - - xce_object.buttons_etc.setLayout(xce_object.data_collection_vbox_for_settings) - xce_object.scroll.setWidget(xce_object.buttons_etc) - - xce_object.initial_model_directory_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nProject Directory: - REQUIRED -', - xce_object.initial_model_directory, - 'Select Project Directory', - xce_object.settings_button_clicked) - - xce_object.reference_directory_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nReference Structure Directory: - OPTIONAL -', - xce_object.reference_directory, - 'Select Reference Structure Directory', - xce_object.settings_button_clicked) - - if xce_object.data_source_file != '': - xce_object.data_source_file_label_text = os.path.join(xce_object.database_directory, - xce_object.data_source_file) - xce_object.data_source_file_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nData Source: - REQUIRED -', - xce_object.data_source_file_label_text, - 'Select Data Source File', - xce_object.settings_button_clicked) - else: - xce_object.data_source_file_label_text = '' - - xce_object.data_source_file_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nData Source: - REQUIRED -', - xce_object.data_source_file_label_text, - 'Select Data Source File', - xce_object.settings_button_clicked) - - xce_object.data_collection_vbox_for_settings.addWidget( - QtGui.QLabel('\n\nData Collection Directory: (e.g. /dls/i04-1/data/2017/lb18145-70) -')) - - settings_beamline_frame = QtGui.QFrame() - settings_beamline_frame.setFrameShape(QtGui.QFrame.StyledPanel) - settings_beamline_vbox = QtGui.QVBoxLayout() - - settings_hbox_beamline_directory = QtGui.QHBoxLayout() - xce_object.beamline_directory_label = QtGui.QLabel(xce_object.beamline_directory) - settings_hbox_beamline_directory.addWidget(xce_object.beamline_directory_label) - settings_button_beamline_directory = QtGui.QPushButton('Select Data Collection Directory') - settings_button_beamline_directory.setMaximumWidth(500) - - settings_button_beamline_directory.clicked.connect(xce_object.settings_button_clicked) - - settings_hbox_beamline_directory.addWidget(settings_button_beamline_directory) - settings_beamline_vbox.addLayout(settings_hbox_beamline_directory) - xce_object.read_agamemnon = QtGui.QCheckBox('Read Agamemnon data structure') - settings_beamline_vbox.addWidget(xce_object.read_agamemnon) - - - -# settings_hbox_datasets_summary_file = QtGui.QHBoxLayout() -# xce_object.datasets_summary_file_label = QtGui.QLabel(xce_object.datasets_summary_file) -# settings_hbox_datasets_summary_file.addWidget(xce_object.datasets_summary_file_label) -# settings_button_datasets_summary_file = QtGui.QPushButton('Select Existing\nCollection Summary File') -# settings_button_datasets_summary_file.setMaximumWidth(247) -# settings_button_datasets_summary_file.clicked.connect(xce_object.settings_button_clicked) -# settings_hbox_datasets_summary_file.addWidget(settings_button_datasets_summary_file) -# -# settings_button_new_datasets_summary_file = QtGui.QPushButton('Assign New\nCollection Summary File') -# settings_button_new_datasets_summary_file.clicked.connect(xce_object.settings_button_clicked) -# settings_button_new_datasets_summary_file.setMaximumWidth(247) -# settings_hbox_datasets_summary_file.addWidget(settings_button_new_datasets_summary_file) -# -# settings_beamline_vbox.addLayout(settings_hbox_datasets_summary_file) - - settings_beamline_frame.setLayout(settings_beamline_vbox) - xce_object.data_collection_vbox_for_settings.addWidget(settings_beamline_frame) - - xce_object.ccp4_scratch_directory_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nCCP4_SCR Directory: - OPTIONAL -', - xce_object.ccp4_scratch_directory, - 'Select CCP4_SCR Directory', - xce_object.settings_button_clicked) - - xce_object.panddas_directory_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nPANDDAs directory: - OPTIONAL -', - xce_object.panddas_directory, - 'Select PanDDA Directory', - xce_object.settings_button_clicked) - - xce_object.html_export_directory_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nHTML export directory: - OPTIONAL -', - xce_object.html_export_directory, - 'Select HTML Export Directory', - xce_object.settings_button_clicked) - - xce_object.group_deposition_directory_label = self.layout_funcs.settings_section_setup \ - (xce_object.data_collection_vbox_for_settings, - '\n\nGroup deposition directory: - OPTIONAL -', - xce_object.group_deposit_directory, - 'Select Group deposition Directory', - xce_object.settings_button_clicked) - - # xce_object.data_collection_vbox_for_settings.setSpacing(0) - xce_object.data_collection_vbox_for_settings.setContentsMargins(30, 30, 30, 30) - - xce_object.buttons_etc.resize(xce_object.buttons_etc.sizeHint().width() + 100, xce_object.buttons_etc.sizeHint() - .height()) \ No newline at end of file diff --git a/helpers/assign_stereochemistry.py b/helpers/assign_stereochemistry.py deleted file mode 100755 index a3b6db05..00000000 --- a/helpers/assign_stereochemistry.py +++ /dev/null @@ -1,72 +0,0 @@ -import os,sys -import glob -from rdkit import Chem -#from rdkit.Chem.EnumerateStereoisomers import EnumerateStereoisomers, StereoEnumerationOptions - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) -import XChemDB - -def enumerateStereoChem(compoundID,sampleDir,db,xtal): - # first need to recreate the original CIF file with phenix.elbow because we cannot be sure - # which program was used to create the initial restrains - # this is because funny things happen to aromatic rings in case the file was made with GRADE - os.chdir(os.path.join(sampleDir,'compound')) - sql = "select CompoundSMILESproduct from mainTable where CrystalName = '%s'" % xtal - query = db.execute_statement(sql) - originalSMILES = query[0][0] - cmd = 'phenix.elbow --smiles="%s" --id=LIG --output=tmp' % (originalSMILES) - os.system(cmd) - - stereosmiles = None - if os.path.isfile(os.path.join(sampleDir,'compound','tmp.pdb')): - pdb = os.path.join(sampleDir,'compound','tmp.pdb') - else: - print 'cannot find tmp.pdb' - pass - mol = Chem.MolFromPDBFile(pdb) - Chem.AssignStereochemistry(mol,cleanIt=True,force=True,flagPossibleStereoCenters=True) - if Chem.FindMolChiralCenters(mol,includeUnassigned=True) == []: - print 'no chiral centres found' - db_dict = {} - db_dict['CompoundStereo'] = 'FALSE' - updateDB(db,db_dict,xtal) - else: - stereosmiles = Chem.MolToSmiles(mol,isomericSmiles=True) - generateRestraints(compoundID,sampleDir,db,stereosmiles,xtal) - -def generateRestraints(compoundID,sampleDir,db,stereosmiles,xtal): - cmd = 'phenix.elbow --smiles="%s" --chiral=enumerate --id=LIG --output=%s' %(stereosmiles,compoundID) - os.system(cmd) - checkFiles(compoundID,sampleDir,db,stereosmiles,xtal) - - -def checkFiles(compoundID,sampleDir,db,stereosmiles,xtal): - foundCIF = False - allCIF = '' - for cif in glob.glob(os.path.join(compoundID + '_*.cif')): - foundCIF = True - allCIF += cif+';' - print '---',cif,'===',allCIF - if foundCIF: - db_dict = {} - db_dict['CompoundStereo'] = 'TRUE' - db_dict['CompoundStereoSMILES'] = stereosmiles - db_dict['CompoundStereoCIFprogram'] = 'phenix.elbow' - db_dict['CompoundStereoCIFs'] = allCIF[:-1] - print '>>>',db_dict - updateDB(db,db_dict,xtal) - -def updateDB(db,db_dict,xtal): - # update stereo field - # update restraintsprogram field - # update stereosmiles - db.update_data_source(xtal, db_dict) - -if __name__=='__main__': - compoundID = sys.argv[1] - sampleDir = sys.argv[2] - xtal = sampleDir[sampleDir.rfind('/')+1:] - database = sys.argv[3] - db=XChemDB.data_source(database) - enumerateStereoChem(compoundID,sampleDir,db,xtal) - diff --git a/helpers/create_png_of_compound.py b/helpers/create_png_of_compound.py deleted file mode 100755 index c8caded2..00000000 --- a/helpers/create_png_of_compound.py +++ /dev/null @@ -1,20 +0,0 @@ -import os,sys -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -from rdkit import Chem -from rdkit.Chem import AllChem -from rdkit.Chem import Draw - - -if __name__=='__main__': - - smiles = sys.argv[1] - compoundID = sys.argv[2] - xtal = sys.argv[3] - inital_model_directory = sys.argv[4] - - mol = Chem.MolFromSmiles(smiles) - AllChem.Compute2DCoords(mol) - - os.chdir(os.path.join(inital_model_directory,xtal,'compound')) - Draw.MolToFile(mol, "{0!s}.png".format(compoundID.replace(' ',''))) diff --git a/helpers/find_best_fitting_ligand.py b/helpers/find_best_fitting_ligand.py deleted file mode 100755 index 5ad2985c..00000000 --- a/helpers/find_best_fitting_ligand.py +++ /dev/null @@ -1,99 +0,0 @@ -import sys, os -import glob - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) -import XChemDB - -def parse_autofit_folder(sampleDir,compoundID): - filenames = ['best.pdb','ligand_fit_1.pdb'] - pdbList = [] - for files in glob.glob(os.path.join(sampleDir,'autofit_ligand',compoundID+'_*','*')): - pdb = files[files.rfind('/')+1:] - if pdb in filenames: - pdbList.append(files) - return pdbList - -def find_input_mtz(sampleDir): - possibleMTZ = ['refine.mtz','init.mtz','dimple.mtz',] - mtzin = None - for mtz in possibleMTZ: - if os.path.isfile(os.path.join(sampleDir,mtz)): - mtzin = os.path.join(sampleDir,mtz) - break - return mtzin - -def calculate_cc(sampleDir,compoundID,db): - xtal = sampleDir[sampleDir.rfind('/') + 1:] - pdbList = parse_autofit_folder(sampleDir,compoundID) - mtzin = find_input_mtz(sampleDir) - for pdb in pdbList: - autofitDir = pdb[:pdb.rfind('/')] - os.chdir(autofitDir) - os.system('phenix.get_cc_mtz_pdb %s %s > phenix.get_cc_mtz_pdb.log' %(pdb,mtzin)) - new_file_links(pdbList) - bestRun, bestCC = parse_cc_log(sampleDir, compoundID) - changeLinks(sampleDir, pdbList, bestRun, compoundID) - fitting_program = None - if 'phenix' in bestRun: - fitting_program = 'phenix.ligandfit' - elif 'rhofit' in bestRun: - fitting_program = 'rhofit' - db_dict = {} - db_dict['CompoundAutofitprogram'] = fitting_program - db_dict['CompoundAutofitCC'] = str(bestCC) - updateDB(db, db_dict, xtal) - - -def new_file_links(pdbList): - for pdb in pdbList: - autofitDir = pdb[:pdb.rfind('/')] - autofitRun = pdb.split('/')[len(pdb.split('/')) - 2] - pdbFile = pdb[pdb.rfind('/')+1:] - os.chdir(autofitDir) - if not os.path.isfile(autofitRun+'.pdb'): - os.system('ln -s %s %s.pdb' %(pdbFile,autofitRun)) - -def changeLinks(sampleDir,pdbList,bestRun,compoundID): - os.chdir(sampleDir) - for pdb in pdbList: - autofitDir = pdb.split('/')[len(pdb.split('/')) - 2] - if autofitDir == bestRun: - if os.path.isfile(pdb.replace(sampleDir,'.')): - os.system('/bin/rm %s.pdb' %compoundID) - os.system('ln -s %s %s.pdb' %(pdb.replace(sampleDir,'.'),compoundID)) - -def parse_cc_log(sampleDir,compoundID): - ccDict = {} - ccList = [] - for ccLog in glob.glob(os.path.join(sampleDir,'autofit_ligand',compoundID+'_*','phenix.get_cc_mtz_pdb.log')): - autofitDir = ccLog.split('/')[len(ccLog.split('/'))-2] - for line in open(ccLog): - if line.startswith('local CC:') and len(line.split()) > 2: - cc = line.split()[2] - ccList.append(float(cc)) - ccDict[autofitDir] = cc - break - bestRun = None - try: - bestCC = max(ccList) - for ccRun in ccDict: - print ccRun,ccDict[ccRun],bestCC - if str(ccDict[ccRun]) == str(bestCC): - bestRun = ccRun - break - except ValueError: - pass - return bestRun, bestCC - - -def updateDB(db,db_dict,xtal): - db.update_data_source(xtal, db_dict) - - -if __name__ == '__main__': - compoundID = sys.argv[1] - sampleDir = sys.argv[2] - database = sys.argv[3] - db=XChemDB.data_source(database) - - calculate_cc(sampleDir, compoundID, db) \ No newline at end of file diff --git a/helpers/make_ligand_links_after_pandda.py b/helpers/make_ligand_links_after_pandda.py deleted file mode 100755 index 878d42b7..00000000 --- a/helpers/make_ligand_links_after_pandda.py +++ /dev/null @@ -1,27 +0,0 @@ -# last edited: 10/08/2017, 15:00 - -import os,glob -import sys - -#projectDir='/dls/labxchem/data/2017/lb13385-109/processing/analysis/initial_model_cov' -#panddaDir='/dls/labxchem/data/2017/lb13385-109/processing/analysis/panddas_cov' - - -def make_links(projectDir,panddaDir): - os.chdir(os.path.join(panddaDir,'processed_datasets')) - for xtal in glob.glob('*'): -# for cif in glob.glob(os.path.join(xtal,'ligand_files','*.cif')): -# print cif -# os.system('/bin/rm %s' %cif) -# for pdb in glob.glob(os.path.join(xtal,'ligand_files','*.pdb')): -# print pdb -# os.system('/bin/rm %s' %pdb) - - for pdb in glob.glob(os.path.join(projectDir,xtal,'compound','*.pdb')): - os.system('ln -s %s %s/ligand_files' %(pdb,xtal)) - for cif in glob.glob(os.path.join(projectDir,xtal,'compound','*.cif')): - os.system('ln -s %s %s/ligand_files' %(cif,xtal)) - -if __name__=='__main__': - projectDir=sys.argv[1] - panddaDir=sys.argv[2] \ No newline at end of file diff --git a/helpers/phenix_find_TLS_groups.py b/helpers/phenix_find_TLS_groups.py deleted file mode 100755 index ec96ce1e..00000000 --- a/helpers/phenix_find_TLS_groups.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/local/python/python2.7.3/bin/python -import os -import sys - -def FindTLSgroups(pdbFile): - print '\n==> XCE @ helpers: running phenix.find_tls_groups on new pdb file' - os.system('phenix.find_tls_groups {0!s} > phenix.find_tls_groups.out'.format(pdbFile)) - GroupNames = ['A','B','C','D','E','F','G','H','I','J','K','L','M', - 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] - OutRefmac = '' - found = 0 - i = 0 - for line in open('phenix.find_tls_groups.out'): - if found: - if line.startswith('}'): - break - temp = [line.split()] - OutRefmac = OutRefmac + '\nTLS {0!s}\nRANGE '.format((GroupNames)[i]) + str(temp[0][3])[:-1] + ' ' + \ - str(temp[0][6]) +'.\' ' + str(temp[0][3])[:-1] + ' ' + str(temp[0][8]) + '.\' ALL\n' - i += 1 - if line.startswith('refinement.refine.adp {'): - found = 1 - f = open('refmac.tls','w') - f.write(OutRefmac) - f.close() - - OutPhenix='' - found=0 - for line in open('phenix.find_tls_groups.out'): - if found: - OutPhenix=OutPhenix+line - if line.startswith('}'): - break - if line.startswith('refinement.refine.adp {'): - found=1 - OutPhenix=OutPhenix+line - f = open('phenix.tls','w') - f.write(OutPhenix) - f.close() - - -if __name__=='__main__': - pdbFile = sys.argv[1] - FindTLSgroups(pdbFile) diff --git a/helpers/prepare_for_zenodo_upload.py b/helpers/prepare_for_zenodo_upload.py deleted file mode 100755 index a836c6f5..00000000 --- a/helpers/prepare_for_zenodo_upload.py +++ /dev/null @@ -1,102 +0,0 @@ -# last edited: 13/01/2017, 15:00 - -import os,sys -import glob - -def copy_files(htmlDir): - os.chdir(htmlDir) - if not os.path.isdir('zenodo'): - os.mkdir('zenodo') - os.chdir(os.path.join(htmlDir,'zenodo')) - - print 'copying compoundImages' - os.system('/bin/cp ../compoundImages/* .') - - print 'copying pdbs' - os.system('/bin/cp ../pdbs/* .') - - print 'copying maps' - os.system('/bin/cp ../maps/* .') - - print 'copying residueplots' - os.system('/bin/cp ../residueplots/* .') - - print 'copying mapImages' - os.system('/bin/cp ../mapImages/* .') - - print 'copying icbs' - os.system('/bin/cp ../icbs/* .') - - print 'copying css' - os.system('/bin/cp ../css/* .') - - print 'copying js' - os.system('/bin/cp ../js/* .') - -def edit_index_html(htmlDir,uploadID): - os.chdir(os.path.join(htmlDir,'zenodo')) - - out='' - for line in open('../index.html'): - if 'compoundImages/' in line: - line=line.replace('compoundImages/','https://zenodo.org/record/'+uploadID+'/files/') - if 'pdbs/' in line: - line=line.replace('pdbs/','https://zenodo.org/record/'+uploadID+'/files/') - if 'maps/' in line: - line=line.replace('maps/','https://zenodo.org/record/'+uploadID+'/files/') - if 'residueplots/' in line: - line=line.replace('residueplots/','https://zenodo.org/record/'+uploadID+'/files/') - if 'mapImages/' in line: - line=line.replace('mapImages/','https://zenodo.org/record/'+uploadID+'/files/') - if 'icbs/' in line: - line=line.replace('icbs/','https://zenodo.org/record/'+uploadID+'/files/') - if 'css/' in line: - line=line.replace('css/','https://zenodo.org/record/'+uploadID+'/files/') - if 'js/' in line: - line=line.replace('js/','https://zenodo.org/record/'+uploadID+'/files/') - out+=line - - print 'writing index.html to',os.path.join(htmlDir,'zenodo') - f=open('0_index.html','w') - f.write(out) - f.close() - -def edit_icb_html_files(htmlDir,uploadID): - # https://zenodo.org/record/48768/files/README.txt - os.chdir(os.path.join(htmlDir,'zenodo')) - for file in glob.glob('*event*html'): - out='' - for line in open(file): - if 'src="http://molsoft.com/lib/acticm.js">' in line: - line=line.replace('src="http://molsoft.com/lib/acticm.js">','src="https://molsoft.com/lib/acticm.js">') - if '../mapImages/' in line: - line=line.replace('../mapImages/','https://zenodo.org/record/'+uploadID+'/files/') - if '../compoundImages/' in line: - line=line.replace('../compoundImages/','https://zenodo.org/record/'+uploadID+'/files/') - if ' act.projectFile = "' in line: - line=line.replace(' act.projectFile = "',' act.projectFile = "https://zenodo.org/record/'+uploadID+'/files/') - out+=line - print 'updating',file - f=open(file,'w') - f.write(out) - f.close() - - -if __name__=='__main__': - - print len(sys.argv) - - if len(sys.argv) == 2: - htmlDir=sys.argv[1] - if os.path.isdir(htmlDir): - copy_files(htmlDir) - - elif len(sys.argv) == 3: - htmlDir=sys.argv[1] - uploadID=sys.argv[2] - if os.path.isdir(htmlDir): - edit_index_html(htmlDir,uploadID) - edit_icb_html_files(htmlDir,uploadID) - - else: - print 'wrong input!' diff --git a/helpers/reset_interesting_datasets.py b/helpers/reset_interesting_datasets.py deleted file mode 100755 index 9f89959c..00000000 --- a/helpers/reset_interesting_datasets.py +++ /dev/null @@ -1,38 +0,0 @@ -# last edited: 01/03/2017, 15:00 - -import os,glob -import sys - -def relink_interesting_datasets(panddaDir): - os.chdir(os.path.join(panddaDir,'interesting_datasets')) - dirList=[] - for dirs in glob.glob('*'): - if os.path.isdir(dirs): - dirList.append(dirs) - - for dirs in dirList: - print '/bin/rm -fr {0!s}'.format(dirs) - os.system('/bin/rm -fr {0!s}'.format(dirs)) - print 'ln -s ../processed_datasets/{0!s} .'.format(dirs) - os.system('ln -s ../processed_datasets/{0!s} .'.format(dirs)) - -def check_interesting_datasets(panddaDir): - - os.chdir(os.path.join(panddaDir,'interesting_datasets')) - for xtal in sorted(glob.glob('*')): - if not os.path.islink(xtal): -# print xtal -# print os.path.join(panddaDir,'interesting_datasets',xtal,'modelled_structures',xtal+'-pandda-model.pdb') - if os.path.isfile(os.path.join(panddaDir,'interesting_datasets',xtal,'modelled_structures',xtal+'-pandda-model.pdb')): - print 'mv --backup=numbered {0!s} {1!s}'.format(os.path.join(panddaDir,'interesting_datasets',xtal,'modelled_structures'), os.path.join(panddaDir,'processed_datasets',xtal)) - os.system('mv --backup=numbered {0!s} {1!s}'.format(os.path.join(panddaDir,'interesting_datasets',xtal,'modelled_structures'), os.path.join(panddaDir,'processed_datasets',xtal))) - print 'cp {0!s} {1!s}'.format(os.path.join(panddaDir,'interesting_datasets',xtal,'*params'), os.path.join(panddaDir,'processed_datasets',xtal)) - os.system('cp {0!s} {1!s}'.format(os.path.join(panddaDir,'interesting_datasets',xtal,'*params'), os.path.join(panddaDir,'processed_datasets',xtal))) - - - - -if __name__=='__main__': - panddaDir=sys.argv[1] - check_interesting_datasets(panddaDir) - relink_interesting_datasets(panddaDir) \ No newline at end of file diff --git a/helpers/resort_ligand_atoms.py b/helpers/resort_ligand_atoms.py deleted file mode 100755 index 59d8d05a..00000000 --- a/helpers/resort_ligand_atoms.py +++ /dev/null @@ -1,102 +0,0 @@ -# last edited: 07/06/2017, 17:00 - -import os,sys -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -def get_atom_order_of_ensemble_model(ensembleModel): - - ligandResnames = ['LIG','FRS','DRG','UNL'] - - ensembleLIGdir = {} - - for line in open(ensembleModel): - if line.startswith('ATOM') or line.startswith('HETATM'): - atomName_line= str(line[11:16]) - altLoc_line= str(line[16:17]) - resname_line= str(line[17:20]) - chainID_line= str(line[20:23]) - resseq_line= str(line[23:26]) - - residueID = resname_line.replace(' ','')+'-'+\ - chainID_line.replace(' ','')+'-'+\ - resseq_line.replace(' ','')+'-'+\ - chainID_line.replace(' ','')+'-'+\ - altLoc_line - - if resname_line in ligandResnames: - if residueID not in ensembleLIGdir: - ensembleLIGdir[residueID]=[] - ensembleLIGdir[residueID].append([atomName_line,altLoc_line,resname_line,chainID_line,resseq_line]) - - return ensembleLIGdir - -def resort_ligand_atoms_in_refined_model(refinedModel,ensembleLIGdir): - ligandResnames = ['LIG','FRS','DRG','UNL'] - out='' - refineLIGDir={} - LIGlineAdditional='' - LIGlist=[] - for line in open(refinedModel): - if line.startswith('ATOM') or line.startswith('HETATM'): - altLoc_line= str(line[16:17]) - resname_line= str(line[17:20]) - chainID_line= str(line[20:23]) - resseq_line= str(line[23:26]) - - residueID = resname_line.replace(' ','')+'-'+\ - chainID_line.replace(' ','')+'-'+\ - resseq_line.replace(' ','')+'-'+\ - chainID_line.replace(' ','')+'-'+\ - altLoc_line - - if residueID in ensembleLIGdir: - if residueID not in refineLIGDir: - refineLIGDir[residueID]=[] - else: - # if a ligand was for modelled after pandda.inspect - LIGlineAdditional+=line - refineLIGDir[residueID].append(line) - - - LIGline='' - for ligand in ensembleLIGdir: - for atomLine in ensembleLIGdir[ligand]: - atomName=atomLine[0] - for line in refineLIGDir[ligand]: - atomName_line=str(line[11:16]) - if atomName_line==atom: - LIGline+=line - break - - for line in open(refinedModel): - if line.startswith('ATOM') or line.startswith('HETATM'): - resname_line= str(line[17:20]) - if resname_line in ligandResnames: - continue - else: - out+=line - - elif line.startswith('END'): - continue - - elif line.startswith('TER'): - continue - - else: - out+=line - - out+=LIGline - out+='END\n' - - os.system('/bin/mv %s %s' %(refinedModel,refinedModel.replace('.pdb','_original_atom_order.pdb'))) - f=open(refinedModel,'w') - f.write(out) - f.close() - - - -if __name__=='__main__': - ensembleModel=sys.argv[1] - refinedModel=sys.argv[2] - ensembleLIGdir=get_atom_order_of_ensemble_model(ensembleModel) - resort_ligand_atoms_in_refined_model(refinedModel,ensembleLIGdir) \ No newline at end of file diff --git a/helpers/select_ground_state_dataset.py b/helpers/select_ground_state_dataset.py deleted file mode 100755 index 0527cf14..00000000 --- a/helpers/select_ground_state_dataset.py +++ /dev/null @@ -1,111 +0,0 @@ -# last edited: 03/08/2017, 15:00 - -import os,sys -import glob -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -from XChemUtils import parse -from XChemUtils import mtztools - - -# - select datasets with highest resolution -# - select only those without an event map -# - take the one with the lowest Rfree - - -def find_highest_resolution_datasets(panddaDir): - found=False - datasetList=[] - for logFile in glob.glob(os.path.join(panddaDir,'logs','*.log')): - for n,line in enumerate(open(logFile)): - if line.startswith('Statistical Electron Density Characterisation') and len(line.split()) == 6: - resolution=line.split()[5] - found=True - foundLine=n - if found and n>=foundLine+3: - if line.startswith('---'): - break - else: - tmpLine=line.replace(' ','').replace('\t','').replace('\n','').replace('\r','') - for item in tmpLine.split(','): - if item != '': - datasetList.append(item) - print datasetList - return datasetList - -def get_datasets_without_event_map(panddaDir,datasetList): - datasetListwithoutEvent=[] - for dataset in datasetList: - noEvent=True - for files in glob.glob(os.path.join(panddaDir,'processed_datasets',dataset,'*')): - if 'event' in files: - noEvent=False - break - if noEvent: - datasetListwithoutEvent.append(dataset) - print datasetListwithoutEvent - return datasetListwithoutEvent - -def select_dataset_with_lowest_Rfree(panddaDir,datasetListwithoutEvent): - datasetList=[] - lowestRfree='' - for dataset in datasetListwithoutEvent: - if os.path.isfile(os.path.join(panddaDir,'processed_datasets',dataset,dataset+'-pandda-input.pdb')): - stats=parse().PDBheader(os.path.join(panddaDir,'processed_datasets',dataset,dataset+'-pandda-input.pdb')) - Rfree=stats['Rfree'] - try: - print dataset,Rfree,stats['ResolutionHigh'] - datasetList.append([dataset,float(Rfree)]) - except ValueError: - pass - if datasetList: - lowestRfree=min(datasetList,key=lambda x: x[1])[0] - return lowestRfree - -def link_pdb_mtz_files(panddaDir,lowestRfree): - targetDir='/'.join(panddaDir.split('/')[:len(panddaDir.split('/'))-1]) - panddaFolder=panddaDir.split('/')[len(panddaDir.split('/'))-1] - print targetDir - print panddaFolder - os.chdir(targetDir) - if os.path.isfile(os.path.join(panddaDir,'processed_datasets',lowestRfree,lowestRfree+'-pandda-input.pdb')): - os.system('/bin/rm %s-ground-state.pdb 2> /dev/null' %lowestRfree) - os.symlink(os.path.join(panddaFolder,'processed_datasets',lowestRfree,lowestRfree+'-pandda-input.pdb'),lowestRfree+'-ground-state.pdb') - if os.path.isfile(os.path.join(panddaDir,'processed_datasets',lowestRfree,lowestRfree+'-pandda-input.mtz')): - os.system('/bin/rm %s-ground-state.free.mtz 2> /dev/null' %lowestRfree) - os.symlink(os.path.join(panddaFolder,'processed_datasets',lowestRfree,lowestRfree+'-pandda-input.mtz'),lowestRfree+'-ground-state.free.mtz') - - if os.path.isfile(os.path.join(panddaDir,'processed_datasets',lowestRfree,lowestRfree+'-ground-state-mean-map.native.ccp4')): - os.system('/bin/rm %s-ground-state-mean-map.native.ccp4 2> /dev/null' %lowestRfree) - os.symlink(os.path.join(panddaFolder,'processed_datasets',lowestRfree,lowestRfree+'-ground-state-mean-map.native.ccp4'),lowestRfree+'-ground-state-mean-map.native.ccp4') - elif os.path.isfile(os.path.join(panddaDir,'processed_datasets',lowestRfree,lowestRfree+'-ground-state-average-map.native.ccp4')): - os.system('/bin/rm %s-ground-state-mean-map.native.ccp4 2> /dev/null' %lowestRfree) - os.symlink(os.path.join(panddaFolder,'processed_datasets',lowestRfree,lowestRfree+'-ground-state-average-map.native.ccp4'),lowestRfree+'-ground-state-mean-map.native.ccp4') - - convert_mean_map_to_mtz(lowestRfree+'-ground-state-mean-map.native.ccp4',lowestRfree+'-ground-state.free.mtz') - - -def convert_mean_map_to_mtz(emap,mtz): - print 'converting ground-state-mean-map to MTZ' - cmd = ('mapmask MAPIN %s MAPOUT %s << eof\n' % (emap, emap.replace('.ccp4', '.P1.ccp4')) + - ' XYZLIM CELL\n' - ' PAD 0.0\n' - ' SYMMETRY 1\n' - 'eof\n') - print cmd - os.system(cmd) - print '--->',mtz - reso = mtztools(mtz).get_dmin() - print '-> resolution:',reso - cmd = ('module load phenix\n' - 'phenix.map_to_structure_factors %s d_min=%s\n' % (emap.replace('.ccp4', '.P1.ccp4'), reso) + - '/bin/mv map_to_structure_factors.mtz %s' % emap.replace('.ccp4', '.mtz')) - print cmd - os.system(cmd) - -if __name__=='__main__': - panddaDir=sys.argv[1] - datasetList=find_highest_resolution_datasets(panddaDir) - datasetListwithoutEvent=get_datasets_without_event_map(panddaDir,datasetList) - lowestRfree=select_dataset_with_lowest_Rfree(panddaDir,datasetListwithoutEvent) - link_pdb_mtz_files(panddaDir,lowestRfree) diff --git a/helpers/update_data_source_after_refinement.py b/helpers/update_data_source_after_refinement.py deleted file mode 100755 index 7aca6e3e..00000000 --- a/helpers/update_data_source_after_refinement.py +++ /dev/null @@ -1,234 +0,0 @@ -# last edited: 27/07/2016, 17:00 - -import os,sys -import glob -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -from XChemUtils import parse -from XChemUtils import pdbtools -from XChemUtils import misc -import XChemDB -import csv - - -def parse_pdb(inital_model_directory,xtal,db_dict): - if os.path.isfile(os.path.join(inital_model_directory,xtal,'refine.pdb')): - db_dict['RefinementPDB_latest']=os.path.realpath(os.path.join(inital_model_directory,xtal,'refine.pdb')) - pdb=parse().PDBheader(os.path.join(inital_model_directory,xtal,'refine.pdb')) - db_dict['RefinementRcryst'] = pdb['Rcryst'] - db_dict['RefinementRcrystTraficLight'] = pdb['RcrystTL'] - db_dict['RefinementRfree']= pdb['Rfree'] - db_dict['RefinementRfreeTraficLight'] = pdb['RfreeTL'] - db_dict['RefinementRmsdBonds'] = pdb['rmsdBonds'] - db_dict['RefinementRmsdBondsTL'] = pdb['rmsdBondsTL'] - db_dict['RefinementRmsdAngles'] = pdb['rmsdAngles'] - db_dict['RefinementRmsdAnglesTL'] = pdb['rmsdAnglesTL'] - db_dict['RefinementSpaceGroup'] = pdb['SpaceGroup'] - db_dict['RefinementResolution'] = pdb['ResolutionHigh'] - db_dict['RefinementResolutionTL'] = pdb['ResolutionColor'] - db_dict['RefinementStatus'] = 'finished' - else: - db_dict['RefinementStatus'] = 'failed' - - if os.path.isfile(os.path.join(inital_model_directory,xtal,'refine.bound.pdb')): - db_dict['RefinementBoundConformation']=os.path.realpath(os.path.join(inital_model_directory,xtal,'refine.bound.pdb')) - elif os.path.isfile(os.path.join(inital_model_directory,xtal,'refine.split.bound-state.pdb')): - db_dict['RefinementBoundConformation']=os.path.realpath(os.path.join(inital_model_directory,xtal,'refine.split.bound-state.pdb')) - elif os.path.isfile(os.path.join(inital_model_directory,xtal,'refine.pdb')): - db_dict['RefinementBoundConformation']=os.path.realpath(os.path.join(inital_model_directory,xtal,'refine.pdb')) - - print db_dict - - return db_dict - -def parse_mtz(inital_model_directory,xtal,db_dict): - if os.path.isfile(os.path.join(inital_model_directory,xtal,'refine.mtz')): - db_dict['RefinementMTZ_latest']=os.path.realpath(os.path.join(inital_model_directory,xtal,'refine.mtz')) - return db_dict - -def check_refmac_matrix_weight(refinement_directory,db_dict): - if os.path.isfile(os.path.join(refinement_directory,'refmac.log')): - logFile=os.path.join(refinement_directory,'refmac.log') - else: - logFile='' - for files in glob.glob(os.path.join(refinement_directory,'*refine.log')): - logFile=files - break - if os.path.isfile(logFile): - for line in open(logFile): - if line.startswith(' Weight matrix') and len(line.split()) == 3: - db_dict['RefinementMatrixWeight'] = line.split()[2] - return db_dict - -def check_refmac_logfile(refinement_directory,db_dict): - if os.path.isfile(os.path.join(refinement_directory,'refmac.log')): - logFile=os.path.join(refinement_directory,'refmac.log') - else: - logFile='' - for files in glob.glob(os.path.join(refinement_directory,'*refine.log')): - logFile=files - break - if os.path.isfile(logFile): - for line in open(logFile): - if 'Your coordinate file has a ligand which has either minimum or no description in the library' in line: - db_dict['RefinementStatus'] = 'CIF problem' - return db_dict - -def parse_molprobity_output(inital_model_directory,xtal,db_dict): - if os.path.isfile(os.path.join(inital_model_directory,xtal,'validation_summary.txt')): - for line in open(os.path.join(inital_model_directory,xtal,'validation_summary.txt')): - if 'molprobity score' in line.lower(): - if len(line.split()) >= 4: - db_dict['RefinementMolProbityScore'] = line.split()[3] - if float(line.split()[3]) < 2: - db_dict['RefinementMolProbityScoreTL'] = 'green' - if 2 <= float(line.split()[3]) < 3: - db_dict['RefinementMolProbityScoreTL'] = 'orange' - if float(line.split()[3]) >= 3: - db_dict['RefinementMolProbityScoreTL'] = 'red' - - if 'ramachandran outliers' in line.lower(): - if len(line.split()) >= 4: - db_dict['RefinementRamachandranOutliers'] = line.split()[3] - - if float(line.split()[3]) < 0.3: - db_dict['RefinementRamachandranOutliersTL'] = 'green' - if 0.3 <= float(line.split()[3]) < 1: - db_dict['RefinementRamachandranOutliersTL'] = 'orange' - if float(line.split()[3]) >= 1: - db_dict['RefinementRamachandranOutliersTL'] = 'red' - - if 'favored' in line.lower(): - if len(line.split()) >= 3: - db_dict['RefinementRamachandranFavored'] = line.split()[2] - if float(line.split()[2]) < 90: - db_dict['RefinementRamachandranFavoredTL'] = 'red' - if 90 <= float(line.split()[2]) < 98: - db_dict['RefinementRamachandranFavoredTL'] = 'orange' - if float(line.split()[2]) >= 98: - db_dict['RefinementRamachandranFavoredTL'] = 'green' - - return db_dict - - -def parse_ligand_validation(inital_model_directory,refinement_directory,xtal): - if os.path.isfile(os.path.join(refinement_directory, 'residue_scores.csv')): - with open(os.path.join(refinement_directory, 'residue_scores.csv'), 'rb') as csv_import: - csv_dict = csv.DictReader(csv_import) - for i, line in enumerate(csv_dict): - db_pandda_dict = {} - residue = line[''].replace(' ','') - residueFilename = line[''] - if len(residue.split('-')) == 2: -# residue_name = residue.split('-')[0] -# print residue_name - residue_chain = residue.split('-')[0] - residue_number = residue.split('-')[1] - residue_xyz = pdbtools(os.path.join(inital_model_directory, xtal, 'refine.pdb')).get_center_of_gravity_of_residue_ish(residue_chain, residue_number) - event = db.execute_statement("select PANDDA_site_x,PANDDA_site_y,PANDDA_site_z,PANDDA_site_index from panddaTable where CrystalName='{0!s}'".format(xtal)) - for coord in event: - db_pandda_dict = {} - event_x = float(str(coord[0])) - event_y = float(str(coord[1])) - event_z = float(str(coord[2])) - site_index = str(coord[3]) - distance = misc().calculate_distance_between_coordinates(residue_xyz[0], residue_xyz[1],residue_xyz[2], - event_x, event_y,event_z) - print 'distance',distance - # if coordinate of ligand and event are closer than 7A, then we assume they belong together - if distance < 7: - db_pandda_dict['PANDDA_site_ligand_id'] = residue - db_pandda_dict['PANDDA_site_occupancy'] = line['Occupancy'] - db_pandda_dict['PANDDA_site_B_average'] = line['Average B-factor (Residue)'] - db_pandda_dict['PANDDA_site_B_ratio_residue_surroundings'] = line['Surroundings B-factor Ratio'] - db_pandda_dict['PANDDA_site_rmsd'] = line['Model RMSD'] - db_pandda_dict['PANDDA_site_RSCC'] = line['RSCC'] - db_pandda_dict['PANDDA_site_RSR'] = line['RSR'] - db_pandda_dict['PANDDA_site_RSZD'] = line['RSZD'] - if os.path.isfile(os.path.join(refinement_directory, 'residue_plots', residueFilename + '.png')): - db_pandda_dict['PANDDA_site_spider_plot'] = os.path.join(refinement_directory, - 'residue_plots', - residueFilename + '.png') - else: - db_pandda_dict['PANDDA_site_spider_plot'] = '' - - if db_pandda_dict != {}: - print '==> XCE: updating pandda Table of data source' - db.update_panddaTable(xtal, site_index, db_pandda_dict) - -def update_ligand_information_in_panddaTable(inital_model_directory,xtal): - if os.path.isfile(os.path.join(inital_model_directory, xtal, 'refine.pdb')): -# ligands_in_file=pdbtools(os.path.join(inital_model_directory, xtal, 'refine.pdb')).find_xce_ligand_details() - ligands_in_file=pdbtools(os.path.join(inital_model_directory, xtal, 'refine.pdb')).get_residues_with_resname('LIG') - for ligand in ligands_in_file: -# residue_name= ligand[0] -# residue_chain= ligand[1] -# residue_number= ligand[2] -# residue_altLoc= ligand[3] - residue_name= ligand[0] - residue_chain= ligand[2] - residue_number= ligand[1] - residue_altLoc = 'X' - residue_xyz = pdbtools(os.path.join(inital_model_directory, xtal, 'refine.pdb')).get_center_of_gravity_of_residue_ish(residue_chain, residue_number) - event = db.execute_statement("select PANDDA_site_x,PANDDA_site_y,PANDDA_site_z,PANDDA_site_index from panddaTable where CrystalName='{0!s}'".format(xtal)) - for coord in event: - db_pandda_dict = {} - event_x = float(str(coord[0])) - event_y = float(str(coord[1])) - event_z = float(str(coord[2])) - site_index = str(coord[3]) - distance = misc().calculate_distance_between_coordinates(residue_xyz[0], residue_xyz[1],residue_xyz[2], - event_x, event_y,event_z) - # if coordinate of ligand and event are closer than 7A, then we assume they belong together - if distance < 7: - db_pandda_dict['PANDDA_site_ligand_resname'] = residue_name - db_pandda_dict['PANDDA_site_ligand_chain'] = residue_chain - db_pandda_dict['PANDDA_site_ligand_sequence_number'] = residue_number - db_pandda_dict['PANDDA_site_ligand_altLoc'] = residue_altLoc - db_pandda_dict['PANDDA_site_ligand_placed'] = 'True' - if db_pandda_dict != {}: - print '==> XCE: updating pandda Table of data source' - db.update_panddaTable(xtal, site_index, db_pandda_dict) - - - -def update_data_source(db_dict): - if db_dict != {}: - print '==> xce: updating mainTable of data source' - db.update_data_source(xtal,db_dict) - # update refinement outcome if necessary - sqlite = ( - "update mainTable set RefinementOutcome = '3 - In Refinement' where CrystalName is '{0!s}' ".format(xtal)+ - "and (RefinementOutcome is null or RefinementOutcome is '1 - Analysis Pending' or RefinementOutcome is '2 - PANDDA model')" - ) - db.execute_statement(sqlite) - # now do the same for each site in the pandda table - sqlite = ( - "update panddaTable set RefinementOutcome = '3 - In Refinement' where CrystalName is '{0!s}' ".format(xtal)+ - "and (RefinementOutcome is null or RefinementOutcome is '1 - Analysis Pending' or RefinementOutcome is '2 - PANDDA model')" - ) - db.execute_statement(sqlite) - -if __name__=='__main__': - - print 'hallo' - - db_file=sys.argv[1] - xtal=sys.argv[2] - inital_model_directory=sys.argv[3] - refinement_directory=sys.argv[4] - - db=XChemDB.data_source(db_file) - db_dict={} - - db_dict=parse_pdb(inital_model_directory,xtal,db_dict) - db_dict=parse_mtz(inital_model_directory,xtal,db_dict) - db_dict=check_refmac_matrix_weight(refinement_directory,db_dict) - db_dict=parse_molprobity_output(inital_model_directory,xtal,db_dict) - db_dict=check_refmac_logfile(refinement_directory,db_dict) - - update_ligand_information_in_panddaTable(inital_model_directory,xtal) - - parse_ligand_validation(inital_model_directory,refinement_directory,xtal) - - update_data_source(db_dict) diff --git a/helpers/update_data_source_for_new_cif_files.py b/helpers/update_data_source_for_new_cif_files.py deleted file mode 100755 index 6322d63c..00000000 --- a/helpers/update_data_source_for_new_cif_files.py +++ /dev/null @@ -1,28 +0,0 @@ -# last edited: 22/11/2016, 15:00 - -import os,sys -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -from XChemUtils import parse -import XChemDB - -if __name__=='__main__': - db_file=sys.argv[1] - xtal=sys.argv[2] - initial_model_directory=sys.argv[3] - compoundID=sys.argv[4] - - db=XChemDB.data_source(db_file) - db_dict={} - if os.path.isfile(os.path.join(initial_model_directory,xtal,'compound',compoundID+'.cif')) and \ - os.path.getsize(os.path.join(initial_model_directory,xtal,'compound',compoundID+'.cif')) > 20 : - db_dict['RefinementCIF']=os.path.join(initial_model_directory,xtal,'compound',compoundID+'.cif') - db_dict['RefinementCIFStatus']='restraints generated' - else: - db_dict['RefinementCIF']='' - db_dict['RefinementCIFStatus']='restraints failed' - os.system('/bin/rm '+os.path.join(initial_model_directory,xtal,compoundID.replace(' ','')+'.pdb')) - os.system('/bin/rm '+os.path.join(initial_model_directory,xtal,compoundID.replace(' ','')+'.cif')) - os.system('/bin/rm '+os.path.join(initial_model_directory,xtal,compoundID.replace(' ','')+'.png')) - - db.update_data_source(xtal,db_dict) \ No newline at end of file diff --git a/helpers/update_data_source_for_new_dimple_pdb.py b/helpers/update_data_source_for_new_dimple_pdb.py deleted file mode 100755 index c7614b6a..00000000 --- a/helpers/update_data_source_for_new_dimple_pdb.py +++ /dev/null @@ -1,108 +0,0 @@ -# last edited: 15/11/2016, 15:00 - -import os,sys -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) -import glob - -from iotbx import mtz - -from XChemUtils import parse -import XChemDB - -if __name__=='__main__': - db_file=sys.argv[1] - xtal=sys.argv[2] - inital_model_directory=sys.argv[3] - - db=XChemDB.data_source(db_file) - if os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple.pdb')): - db_dict= {'DimplePathToPDB': os.path.join(inital_model_directory, xtal, 'dimple.pdb')} - dimple_ran_successfully=False - if os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple.mtz')): - db_dict['DimplePathToMTZ']=os.path.join(inital_model_directory,xtal,'dimple.mtz') - dimple_ran_successfully=True - db_dict['DataProcessingDimpleSuccessful']='True' - db_dict['DimpleStatus'] = 'finished' - if not dimple_ran_successfully: - db_dict['DataProcessingDimpleSuccessful']='False' - db_dict['DimpleStatus'] = 'failed' - pdb=parse().PDBheader(os.path.join(inital_model_directory,xtal,'dimple.pdb')) - db_dict['DimpleRcryst']=pdb['Rcryst'] - db_dict['DimpleRfree']=pdb['Rfree'] - db_dict['RefinementOutcome']='1 - Analysis Pending' - db_dict['RefinementSpaceGroup']=pdb['SpaceGroup'] -# if not os.path.isfile(xtal+'.free.mtz'): -# os.chdir(os.path.join(inital_model_directory,xtal)) -# os.system('/bin/rm '+xtal+'.free.mtz') -# if os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','prepared2.mtz')): -# os.symlink(os.path.join('dimple','dimple_rerun_on_selected_file','dimple','prepared2.mtz'),xtal+'.free.mtz') -# db_dict['RefinementMTZfree']=xtal+'.free.mtz' -# elif os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','prepared.mtz')): -# os.symlink(os.path.join('dimple','dimple_rerun_on_selected_file','dimple','prepared.mtz'),xtal+'.free.mtz') -# db_dict['RefinementMTZfree']=xtal+'.free.mtz' - - # setting free.mtz file - - os.chdir(os.path.join(inital_model_directory,xtal)) - os.system('/bin/rm -f %s.free.mtz' %xtal) - mtzFree = None - db_dict['RefinementMTZfree'] = '' - if os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','prepared2.mtz')): - mtzFree = os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','prepared2.mtz') - elif os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','prepared.mtz')): - mtzFree = os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','prepared.mtz') - elif os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple','prepared.mtz')): - mtzFree = os.path.join(inital_model_directory,xtal,'dimple','dimple','prepared.mtz') - elif os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple','prepared2.mtz')): - mtzFree = os.path.join(inital_model_directory,xtal,'dimple','dimple','prepared2.mtz') - elif os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','free.mtz')): - mtzFree = os.path.join(inital_model_directory,xtal,'dimple','dimple_rerun_on_selected_file','dimple','free.mtz') - elif os.path.isfile(os.path.join(inital_model_directory,xtal,'dimple','dimple','free.mtz')): - mtzFree = os.path.join(inital_model_directory,xtal,'dimple','dimple','free.mtz') - - if mtzFree is not None: - if 'F_unique' in mtz.object(mtzFree).column_labels(): - cmd = ( 'cad hklin1 %s hklout %s.free.mtz << eof\n' %(mtzFree,xtal) + - ' monitor BRIEF\n' - ' labin file 1 E1=F E2=SIGF E3=FreeR_flag\n' - ' labout file 1 E1=F E2=SIGF E3=FreeR_flag\n' - 'eof\n' ) - - os.system(cmd) - else: - os.symlink(mtzFree,xtal+'.free.mtz') - - db_dict['RefinementMTZfree']=xtal+'.free.mtz' - - - - - # if no refinement was carried out yet, then we also want to link the dimple files to refine.pdb/refine.log - # so that we can look at them with the COOT plugin - # 15/11/2016: obsolete since COOT will now read dimple.pdb/dimple.mtz if no refine.pdb/refine.mtz is present -# found_previous_refinement=False -# os.chdir(os.path.join(inital_model_directory,xtal)) -# for dirs in glob.glob('*'): -# if os.path.isdir(dirs) and dirs.startswith('Refine_'): -# found_previous_refinement=True -# break -# if not found_previous_refinement: -# # first delete possible old symbolic links -# if os.path.isfile('refine.pdb'): os.system('/bin/rm refine.pdb') -# os.symlink('dimple.pdb','refine.pdb') -# if os.path.isfile('refine.mtz'): os.system('/bin/rm refine.mtz') -# os.symlink('dimple.mtz','refine.mtz') - - # finally, update data source - print '==> xce: updating data source after DIMPLE run' - db.update_data_source(xtal,db_dict) - - else: - # the actual dimple script creates symbolic links regardless if dimple was successful or not - # python os.path.isfile is False if symbolic link points to non existing file - # so we remove all of them! - os.chdir(os.path.join(inital_model_directory,xtal)) - os.system('/bin/rm dimple.pdb') - os.system('/bin/rm dimple.mtz') - os.system('/bin/rm 2fofc.map') - os.system('/bin/rm fofc.map') diff --git a/helpers/update_pandda_status_flag.py b/helpers/update_pandda_status_flag.py deleted file mode 100755 index a55ec20d..00000000 --- a/helpers/update_pandda_status_flag.py +++ /dev/null @@ -1,21 +0,0 @@ -# last edited: 18/11/2016, 15:00 - -import os,sys -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -import XChemDB - - -def update_data_source(db_file,crystalString,status): - db=XChemDB.data_source(db_file) - - print "update mainTable set PANDDAStatus = '{0!s}' where CrystalName in ({1!s})".format(status, "'"+crystalString.replace(",","','")+"'") - db.execute_statement("update mainTable set PANDDAStatus = '{0!s}' where CrystalName in ({1!s})".format(status, "'"+crystalString.replace(",","','")+"'")) - - -if __name__=='__main__': - db_file=sys.argv[1] - crystalString=sys.argv[2] - status=sys.argv[3] - - update_data_source(db_file,crystalString,status) diff --git a/helpers/update_status_flag.py b/helpers/update_status_flag.py deleted file mode 100755 index 3025cb0b..00000000 --- a/helpers/update_status_flag.py +++ /dev/null @@ -1,20 +0,0 @@ -# last edited: 15/11/2016, 15:00 - -import os,sys -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -import XChemDB - - -def update_data_source(db_file,xtal,db_column,status): - db=XChemDB.data_source(db_file) - db_dict= {db_column: status} - db.update_data_source(xtal,db_dict) - -if __name__ == '__main__': - db_file = sys.argv[1] - xtal = sys.argv[2] - db_column = sys.argv[3] - status = sys.argv[4] - - update_data_source(db_file, xtal, db_column, status) diff --git a/launch.py b/launch.py new file mode 100755 index 00000000..12718ae3 --- /dev/null +++ b/launch.py @@ -0,0 +1,10 @@ +import os +import sys + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.XChemExplorer import XChemExplorer + + XChemExplorer(sys.argv[1:]) diff --git a/lib/PuckDB.py b/lib/PuckDB.py deleted file mode 100755 index beffd5a9..00000000 --- a/lib/PuckDB.py +++ /dev/null @@ -1,27 +0,0 @@ -import sqlite3 -import os,sys - -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') - -class puck_db(object): - - def __init__(self,data_base): - - self.data_base=data_base - - - def get_all_pucks_from_DB(self): - print 'hello' - - def insert_mounted_crystals(self): - print 'hello' - - def kill_mounted_cryatsl(self): - print 'hello' - - def change_puck_location(self): - print 'hello' - - def execute_sqlite(self): - print 'hello' - diff --git a/lib/XChemCoot.py b/lib/XChemCoot.py deleted file mode 100755 index f367e923..00000000 --- a/lib/XChemCoot.py +++ /dev/null @@ -1,1560 +0,0 @@ -# last edited: 08/08/2017 - 15:00 - -import gobject -import sys -import os -import pickle -import glob - -from matplotlib.figure import Figure - -# from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas - -# XCE libraries -sys.path.append(os.getenv('XChemExplorer_DIR') + '/lib') -import XChemDB -import XChemRefine -import XChemUtils -import XChemLog - -# libraries from COOT -import pygtk, gtk, pango -import coot - -# had to adapt the original coot_utils.py file -# otherwise unable to import the original file without complaints about missing modules etc. -# modified file is now in $XChemExplorer_DIR/lib -import coot_utils_XChem - - -class GUI(object): - """ - main class which opens the actual GUI - """ - - def __init__(self): - - ########################################################################################### - # read in settings file from XChemExplorer to set the relevant paths - self.settings = pickle.load(open(".xce_settings.pkl", "rb")) - - remote_qsub_submission = self.settings['remote_qsub'] - self.database_directory = self.settings['database_directory'] - self.xce_logfile = self.settings['xce_logfile'] - self.Logfile = XChemLog.updateLog(self.xce_logfile) - self.Logfile.insert('==> COOT: starting coot plugin...') - self.data_source = self.settings['data_source'] - self.db = XChemDB.data_source(self.data_source) - - print self.settings - - # checking for external software packages - self.external_software = XChemUtils.external_software(self.xce_logfile).check() - self.external_software['qsub_remote'] = remote_qsub_submission - - self.selection_criteria = ['0 - All Datasets', - '1 - Analysis Pending', - '2 - PANDDA model', - '3 - In Refinement', - '4 - CompChem ready', - '5 - Deposition ready', - '6 - Deposited', - '7 - Analysed & Rejected'] - - self.experiment_stage = [['Review PANDDA export', '2 - PANDDA model', 65000, 0, 0], - ['In Refinement', '3 - In Refinement', 65000, 0, 0], - ['Comp Chem Ready!', '4 - CompChem ready', 65000, 0, 0], - ['Ready for Deposition!', '5 - Deposition ready', 65000, 0, 0], - ['In PDB', '6 - Deposited', 65000, 0, 0], - ['Analysed & Rejected', '7 - Analysed & Rejected', 65000, 0, 0]] - - self.ligand_confidence_category = ['0 - no ligand present', - '1 - Low Confidence', - '2 - Correct ligand, weak density', - '3 - Clear density, unexpected ligand', - '4 - High Confidence'] - - self.ligand_site_information = self.db.get_list_of_pandda_sites_for_coot() - - # this decides which samples will be looked at - self.selection_mode = '' - # self.selected_site='' - self.pandda_index = -1 # refers to the number of sites - self.site_index = '0' - self.event_index = '0' - - # the Folder is kind of a legacy thing because my inital idea was to have separate folders - # for Data Processing and Refinement - self.project_directory = self.settings['initial_model_directory'] - self.Serial = 0 - self.panddaSerial = 0 - self.Refine = None - self.index = -1 - self.Todo = [] - self.siteDict = {} - - self.xtalID = '' - self.compoundID = '' - self.ground_state_mean_map = '' - self.spider_plot = '' - self.ligand_confidence = '' - self.refinement_folder = '' - self.refinementProtocol = 'pandda_refmac' - # self.datasetOutcome='' - - self.pdb_style = 'refine.pdb' - self.mtz_style = 'refine.mtz' - - self.label = None - - # stores imol of currently loaded molecules and maps - self.mol_dict = {'protein': -1, - 'ligand': -1, - '2fofc': -1, - 'fofc': -1, - 'event': -1} - - # two dictionaries which are flushed when a new crystal is loaded - # and which contain information to update the data source if necessary - self.db_dict_mainTable = {} - self.db_dict_panddaTable = {} - - self.label_button_list = [] - - - ########################################################################################### - # some COOT settings - coot.set_map_radius(17) - coot.set_colour_map_rotation_for_map(0) - # coot.set_colour_map_rotation_on_read_pdb_flag(21) - - self.QualityIndicators = {'RefinementRcryst': '-', - 'RefinementRfree': '-', - 'RefinementRfreeTraficLight': 'gray', - 'RefinementResolution': '-', - 'RefinementResolutionTL': 'gray', - 'RefinementMolProbityScore': '-', - 'RefinementMolProbityScoreTL': 'gray', - 'RefinementRamachandranOutliers': '-', - 'RefinementRamachandranOutliersTL': 'gray', - 'RefinementRamachandranFavored': '-', - 'RefinementRamachandranFavoredTL': 'gray', - 'RefinementRmsdBonds': '-', - 'RefinementRmsdBondsTL': 'gray', - 'RefinementRmsdAngles': '-', - 'RefinementRmsdAnglesTL': 'gray', - 'RefinementMatrixWeight': '-'} - - self.spider_plot_data = {'PANDDA_site_ligand_id': '-', - 'PANDDA_site_occupancy': '-', - 'PANDDA_site_B_average': '-', - 'PANDDA_site_B_ratio_residue_surroundings': '-', - 'PANDDA_site_RSCC': '-', - 'PANDDA_site_rmsd': '-', - 'PANDDA_site_RSR': '-', - 'PANDDA_site_RSZD': '-'} - - # default refmac parameters - self.RefmacParams = {'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': ''} - - # XCE menu - menu = coot_menubar_menu("XCE") - - add_simple_coot_menu_menuitem( - menu, "set all occupanicies to 1", - lambda func: self.reset_occupancy()) - - - def StartGUI(self): - - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_default_size(400, 800) - self.window.set_title("XChemExplorer") - self.vbox = gtk.VBox() # this is the main container - - ################################################################################# - # --- Sample Selection --- - # self.vbox.add(gtk.Label('Select Samples')) - - frame = gtk.Frame(label='Select Samples') - self.hbox_select_samples = gtk.HBox() - # vbox=gtk.VBox() - - self.cb_select_samples = gtk.combo_box_new_text() - self.cb_select_samples.connect("changed", self.set_selection_mode) - for citeria in self.selection_criteria: - self.cb_select_samples.append_text(citeria) - self.hbox_select_samples.add(self.cb_select_samples) - - # self.cb_select_sites = gtk.combo_box_new_text() - # self.cb_select_sites.connect("changed", self.set_site) - # for site in self.ligand_site_information: - # self.cb_select_sites.append_text(str(site[0])+' - '+str(site[1])) - # self.hbox_select_samples.add(self.cb_select_sites) - - self.select_samples_button = gtk.Button(label="GO") - self.select_samples_button.connect("clicked", self.get_samples_to_look_at) - self.hbox_select_samples.add(self.select_samples_button) - frame.add(self.hbox_select_samples) - self.vbox.pack_start(frame) - - ################################################################################# - # --- status window --- - frame = gtk.Frame() - self.status_label = gtk.Label() - frame.add(self.status_label) - self.vbox.pack_start(frame) - - ################################################################################# - # --- refinement protocol --- - frame = gtk.Frame() - self.refinementProtocolcheckbox = gtk.CheckButton('PanDDA model refinement)') - # callback is defined later -# self.refinementProtocolcheckbox.connect("toggled", self.refinementProtocolCallback) - self.refinementProtocolcheckbox.set_active(True) - frame.add(self.refinementProtocolcheckbox) - self.vbox.pack_start(frame) - - ################################################################################# - # --- refinement program --- -# frame = gtk.Frame() -# self.refinementProgramcheckbox = gtk.CheckButton('use PHENIX for giant.quick_refine') -# self.refinementProgramcheckbox.connect("toggled", self.refinementProgramCallback) -# self.refinementProgramcheckbox.set_active(False) -# frame.add(self.refinementProgramcheckbox) -# self.vbox.pack_start(frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- Refinement Statistics --- - # next comes a section which displays some global quality indicators - # a combination of labels and textview widgets, arranged in a table - - RRfreeLabel_frame = gtk.Frame() - self.RRfreeLabel = gtk.Label('R/Rfree') - RRfreeLabel_frame.add(self.RRfreeLabel) - self.RRfreeValue = gtk.Label( - self.QualityIndicators['RefinementRcryst'] + '/' + self.QualityIndicators['RefinementRfree']) - RRfreeBox_frame = gtk.Frame() - self.RRfreeBox = gtk.EventBox() - self.RRfreeBox.add(self.RRfreeValue) - RRfreeBox_frame.add(self.RRfreeBox) - - ResolutionLabel_frame = gtk.Frame() - self.ResolutionLabel = gtk.Label('Resolution') - ResolutionLabel_frame.add(self.ResolutionLabel) - self.ResolutionValue = gtk.Label(self.QualityIndicators['RefinementResolution']) - ResolutionBox_frame = gtk.Frame() - self.ResolutionBox = gtk.EventBox() - self.ResolutionBox.add(self.ResolutionValue) - ResolutionBox_frame.add(self.ResolutionBox) - - MolprobityScoreLabel_frame = gtk.Frame() - self.MolprobityScoreLabel = gtk.Label('MolprobityScore') - MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) - self.MolprobityScoreValue = gtk.Label(self.QualityIndicators['RefinementMolProbityScore']) - MolprobityScoreBox_frame = gtk.Frame() - self.MolprobityScoreBox = gtk.EventBox() - self.MolprobityScoreBox.add(self.MolprobityScoreValue) - MolprobityScoreBox_frame.add(self.MolprobityScoreBox) - - RamachandranOutliersLabel_frame = gtk.Frame() - self.RamachandranOutliersLabel = gtk.Label('Rama Outliers') - RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) - self.RamachandranOutliersValue = gtk.Label(self.QualityIndicators['RefinementRamachandranOutliers']) - RamachandranOutliersBox_frame = gtk.Frame() - self.RamachandranOutliersBox = gtk.EventBox() - self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) - RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) - - RamachandranFavoredLabel_frame = gtk.Frame() - self.RamachandranFavoredLabel = gtk.Label('Rama Favored') - RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) - self.RamachandranFavoredValue = gtk.Label(self.QualityIndicators['RefinementRamachandranFavored']) - RamachandranFavoredBox_frame = gtk.Frame() - self.RamachandranFavoredBox = gtk.EventBox() - self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) - RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) - - rmsdBondsLabel_frame = gtk.Frame() - self.rmsdBondsLabel = gtk.Label('rmsd(Bonds)') - rmsdBondsLabel_frame.add(self.rmsdBondsLabel) - self.rmsdBondsValue = gtk.Label(self.QualityIndicators['RefinementRmsdBonds']) - rmsdBondsBox_frame = gtk.Frame() - self.rmsdBondsBox = gtk.EventBox() - self.rmsdBondsBox.add(self.rmsdBondsValue) - rmsdBondsBox_frame.add(self.rmsdBondsBox) - - rmsdAnglesLabel_frame = gtk.Frame() - self.rmsdAnglesLabel = gtk.Label('rmsd(Angles)') - rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) - self.rmsdAnglesValue = gtk.Label(self.QualityIndicators['RefinementRmsdAngles']) - rmsdAnglesBox_frame = gtk.Frame() - self.rmsdAnglesBox = gtk.EventBox() - self.rmsdAnglesBox.add(self.rmsdAnglesValue) - rmsdAnglesBox_frame.add(self.rmsdAnglesBox) - - MatrixWeightLabel_frame = gtk.Frame() - self.MatrixWeightLabel = gtk.Label('Matrix Weight') - MatrixWeightLabel_frame.add(self.MatrixWeightLabel) - self.MatrixWeightValue = gtk.Label(self.QualityIndicators['RefinementMatrixWeight']) - MatrixWeightBox_frame = gtk.Frame() - self.MatrixWeightBox = gtk.EventBox() - self.MatrixWeightBox.add(self.MatrixWeightValue) - MatrixWeightBox_frame.add(self.MatrixWeightBox) - - ligandIDLabel_frame = gtk.Frame() - self.ligandIDLabel = gtk.Label('Ligand ID') - ligandIDLabel_frame.add(self.ligandIDLabel) - self.ligandIDValue = gtk.Label(self.spider_plot_data['PANDDA_site_ligand_id']) - ligandIDBox_frame = gtk.Frame() - self.ligandIDBox = gtk.EventBox() - self.ligandIDBox.add(self.ligandIDValue) - ligandIDBox_frame.add(self.ligandIDBox) - - ligand_occupancyLabel_frame = gtk.Frame() - self.ligand_occupancyLabel = gtk.Label('occupancy') - ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) - self.ligand_occupancyValue = gtk.Label(self.spider_plot_data['PANDDA_site_occupancy']) - ligand_occupancyBox_frame = gtk.Frame() - self.ligand_occupancyBox = gtk.EventBox() - self.ligand_occupancyBox.add(self.ligand_occupancyValue) - ligand_occupancyBox_frame.add(self.ligand_occupancyBox) - - ligand_BaverageLabel_frame = gtk.Frame() - self.ligand_BaverageLabel = gtk.Label('B average') - ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) - self.ligand_BaverageValue = gtk.Label(self.spider_plot_data['PANDDA_site_B_average']) - ligand_BaverageBox_frame = gtk.Frame() - self.ligand_BaverageBox = gtk.EventBox() - self.ligand_BaverageBox.add(self.ligand_BaverageValue) - ligand_BaverageBox_frame.add(self.ligand_BaverageBox) - - ligand_BratioSurroundingsLabel_frame = gtk.Frame() - self.ligand_BratioSurroundingsLabel = gtk.Label('B ratio') - ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) - self.ligand_BratioSurroundingsValue = gtk.Label( - self.spider_plot_data['PANDDA_site_B_ratio_residue_surroundings']) - ligand_BratioSurroundingsBox_frame = gtk.Frame() - self.ligand_BratioSurroundingsBox = gtk.EventBox() - self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) - ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) - - ligand_RSCCLabel_frame = gtk.Frame() - self.ligand_RSCCLabel = gtk.Label('RSCC') - ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) - self.ligand_RSCCValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSCC']) - ligand_RSCCBox_frame = gtk.Frame() - self.ligand_RSCCBox = gtk.EventBox() - self.ligand_RSCCBox.add(self.ligand_RSCCValue) - ligand_RSCCBox_frame.add(self.ligand_RSCCBox) - - ligand_rmsdLabel_frame = gtk.Frame() - self.ligand_rmsdLabel = gtk.Label('rmsd') - ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) - self.ligand_rmsdValue = gtk.Label(self.spider_plot_data['PANDDA_site_rmsd']) - ligand_rmsdBox_frame = gtk.Frame() - self.ligand_rmsdBox = gtk.EventBox() - self.ligand_rmsdBox.add(self.ligand_rmsdValue) - ligand_rmsdBox_frame.add(self.ligand_rmsdBox) - - ligand_RSRLabel_frame = gtk.Frame() - self.ligand_RSRLabel = gtk.Label('RSR') - ligand_RSRLabel_frame.add(self.ligand_RSRLabel) - self.ligand_RSRValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSR']) - ligand_RSRBox_frame = gtk.Frame() - self.ligand_RSRBox = gtk.EventBox() - self.ligand_RSRBox.add(self.ligand_RSRValue) - ligand_RSRBox_frame.add(self.ligand_RSRBox) - - ligand_RSZDLabel_frame = gtk.Frame() - self.ligand_RSZDLabel = gtk.Label('RSZD') - ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) - self.ligand_RSZDValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSZD']) - ligand_RSZDBox_frame = gtk.Frame() - self.ligand_RSZDBox = gtk.EventBox() - self.ligand_RSZDBox.add(self.ligand_RSZDValue) - ligand_RSZDBox_frame.add(self.ligand_RSZDBox) - - outer_frame = gtk.Frame() - hbox = gtk.HBox() - - frame = gtk.Frame() - self.table_left = gtk.Table(8, 2, False) - self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) - self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) - self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) - self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) - self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) - self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) - self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) - self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) - self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) - self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) - self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) - self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) - self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) - self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) - self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) - self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) - frame.add(self.table_left) - hbox.add(frame) - - frame = gtk.Frame() - self.table_right = gtk.Table(8, 2, False) - self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) - self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) - self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) - self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) - self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) - self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) - self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) - self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) - self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) - self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) - self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) - self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) - self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) - self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) - self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) - self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) - frame.add(self.table_right) - hbox.add(frame) - - outer_frame.add(hbox) - self.vbox.add(outer_frame) - - hbox = gtk.HBox() - button = gtk.Button(label="Show MolProbity to-do list") - button.connect("clicked", self.show_molprobity_to_do) - hbox.add(button) - # --- ground state mean map --- - self.ground_state_mean_map_button = gtk.Button(label="Show ground state mean map") - self.ground_state_mean_map_button.connect("clicked", self.show_ground_state_mean_map) - hbox.add(self.ground_state_mean_map_button) -# self.vbox.add(self.ground_state_mean_map_button) - self.vbox.add(hbox) - - self.vbox.pack_start(frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- hbox for compound picture & spider_plot (formerly: refinement history) --- - frame = gtk.Frame() - self.hbox_for_info_graphics = gtk.HBox() - - # --- compound picture --- - compound_frame = gtk.Frame() - pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_COMPOUND_IMAGE_AVAILABLE.png')) - self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.image = gtk.Image() - self.image.set_from_pixbuf(self.pic) - compound_frame.add(self.image) - self.hbox_for_info_graphics.add(compound_frame) - - # --- Refinement History --- - # self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) - # self.canvas.set_size_request(190, 190) - # self.hbox_for_info_graphics.add(self.canvas) - - # --- Spider Plot --- - spider_plot_frame = gtk.Frame() - spider_plot_pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image = gtk.Image() - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - spider_plot_frame.add(self.spider_plot_image) - self.hbox_for_info_graphics.add(spider_plot_frame) - - frame.add(self.hbox_for_info_graphics) - self.vbox.add(frame) - - ################################################################################# - # --- pandda.inspect user comments --- -# outer_frame = gtk.Frame(label='pandda.inspect comments') -# vbox = gtk.VBox() -# ligand_site_name_label_frame = gtk.Frame() -# ligand_site_name_label = gtk.Label('Site Name') -# ligand_site_name_label_frame.add(ligand_site_name_label) -# ligand_inspect_confidence_label_frame = gtk.Frame() -# ligand_inspect_confidence_label = gtk.Label('Confidence') -# ligand_inspect_confidence_label_frame.add(ligand_inspect_confidence_label) -# ligand_inspect_interesting_label_frame = gtk.Frame() -# ligand_inspect_interesting_label = gtk.Label('Interesting') -# ligand_inspect_interesting_label_frame.add(ligand_inspect_interesting_label) -# ligand_inspect_comment_label_frame = gtk.Frame() -# ligand_inspect_comment_label = gtk.Label('Comment') -# ligand_inspect_comment_label_frame.add(ligand_inspect_comment_label) -# ligand_site_name_value_frame = gtk.Frame() -# self.ligand_site_name_value = gtk.Label('-') -# ligand_site_name_value_frame.add(self.ligand_site_name_value) -# ligand_inspect_confidence_value_frame = gtk.Frame() -# self.ligand_inspect_confidence_value = gtk.Label('-') -# ligand_inspect_confidence_value_frame.add(self.ligand_inspect_confidence_value) -# ligand_inspect_interesting_value_frame = gtk.Frame() -# self.ligand_inspect_interesting_value = gtk.Label('-') -# ligand_inspect_interesting_value_frame.add(self.ligand_inspect_interesting_value) -# ligand_inspect_comment_value_frame = gtk.Frame() -# self.ligand_inspect_comment_value = gtk.Label('-') -# ligand_inspect_comment_value_frame.add(self.ligand_inspect_comment_value) -# -# frame_pandda_inspect_comments_table = gtk.Frame() -# pandda_inspect_comments_table = gtk.Table(2, 6, False) -# pandda_inspect_comments_table.attach(ligand_site_name_label_frame, 0, 1, 0, 1) -# pandda_inspect_comments_table.attach(ligand_site_name_value_frame, 1, 2, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_confidence_label_frame, 2, 3, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_confidence_value_frame, 3, 4, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_interesting_label_frame, 4, 5, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_interesting_value_frame, 5, 6, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_comment_label_frame, 0, 1, 1, 2) -# pandda_inspect_comments_table.attach(ligand_inspect_comment_value_frame, 1, 6, 1, 2) -# -# frame_pandda_inspect_comments_table.add(pandda_inspect_comments_table) -# vbox.add(frame_pandda_inspect_comments_table) -# outer_frame.add(vbox) -# self.vbox.pack_start(outer_frame) - - # # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - outer_frame = gtk.Frame(label='Sample Navigator') - hboxSample = gtk.HBox() - - # --- crystal navigator combobox --- - frame = gtk.Frame() - self.vbox_sample_navigator = gtk.VBox() - self.cb = gtk.combo_box_new_text() - self.cb.connect("changed", self.ChooseXtal) - self.vbox_sample_navigator.add(self.cb) - # --- crystal navigator backward/forward button --- - self.PREVbutton = gtk.Button(label="<<<") - self.NEXTbutton = gtk.Button(label=">>>") - self.PREVbutton.connect("clicked", self.ChangeXtal, -1) - self.NEXTbutton.connect("clicked", self.ChangeXtal, +1) - hbox = gtk.HBox() - hbox.pack_start(self.PREVbutton) - hbox.pack_start(self.NEXTbutton) - self.vbox_sample_navigator.add(hbox) - frame.add(self.vbox_sample_navigator) - hboxSample.add(frame) - - # --- site navigator combobox --- - frame = gtk.Frame() - self.vbox_site_navigator = gtk.VBox() - self.cb_site = gtk.combo_box_new_text() - self.cb_site.connect("changed", self.ChooseSite) - self.vbox_site_navigator.add(self.cb_site) - # --- site navigator backward/forward button --- - self.PREVbuttonSite = gtk.Button(label="<<<") - self.NEXTbuttonSite = gtk.Button(label=">>>") - self.PREVbuttonSite.connect("clicked", self.ChangeSite, -1) - self.NEXTbuttonSite.connect("clicked", self.ChangeSite, +1) - hbox = gtk.HBox() - hbox.pack_start(self.PREVbuttonSite) - hbox.pack_start(self.NEXTbuttonSite) - self.vbox_site_navigator.add(hbox) - frame.add(self.vbox_site_navigator) - hboxSample.add(frame) - - outer_frame.add(hboxSample) - self.vbox.add(outer_frame) - - # # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# -# outer_frame = gtk.Frame(label='Label') -# hboxlabel = gtk.HBox() -# -# frame = gtk.Frame() -# hbox = gtk.HBox() -# self.vbox_label = gtk.VBox() -# labels = self.db.get_labels_from_db() -# if len(labels) > 5: -# print '==> sorry, too many labels; cannot display them in panel' -# labels = labels[:5] -# # with radiobuttons, one of them needs to be always on -# # but there will be cases when the user has not assigned a label yet -# # hence, the not_shown button is not shown but gets active -# # if the label has not been set yet -# labels.append('not_shown') -# for n, l in enumerate(labels): -# print n,l -# if n == 0: -# new_button = gtk.RadioButton(None, l) -# else: -# new_button = gtk.RadioButton(new_button, l) -# new_button.connect("toggled", self.label_button_clicked, l) -# if not l == 'not_shown': -# hbox.add(new_button) -# self.label_button_list.append(new_button) -# self.vbox_label.add(hbox) -# frame.add(self.vbox_label) -# -# hboxlabel.add(frame) -# -# outer_frame.add(hboxlabel) -# self.vbox.add(outer_frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- current refinement stage --- - outer_frame = gtk.Frame() - hbox = gtk.HBox() - - frame = gtk.Frame(label='Analysis Status') - vbox = gtk.VBox() - self.experiment_stage_button_list = [] - for n, button in enumerate(self.experiment_stage): - if n == 0: - new_button = gtk.RadioButton(None, button[0]) - else: - new_button = gtk.RadioButton(new_button, button[0]) - new_button.connect("toggled", self.experiment_stage_button_clicked, button[1]) - vbox.pack_start(new_button,False,False,0) -# vbox.add(new_button) - self.experiment_stage_button_list.append(new_button) - frame.add(vbox) - hbox.pack_start(frame) - - # --- ligand confidence --- - frame = gtk.Frame(label='Ligand Confidence') - vbox = gtk.VBox() - self.ligand_confidence_button_list = [] - for n, criteria in enumerate(self.ligand_confidence_category): - if n == 0: - new_button = gtk.RadioButton(None, criteria) - else: - new_button = gtk.RadioButton(new_button, criteria) - new_button.connect("toggled", self.ligand_confidence_button_clicked, criteria) - vbox.pack_start(new_button,False,False,0) -# vbox.add(new_button) - self.ligand_confidence_button_list.append(new_button) - frame.add(vbox) - hbox.pack_start(frame) - - # label section --> start -# frame = gtk.Frame(label='Label') -# vbox = gtk.VBox() -# labels = self.db.get_labels_from_db() -# if len(labels) > 5: -# print '==> sorry, too many labels; cannot display them in panel' -# labels = labels[:5] -# # with radiobuttons, one of them needs to be always on -# # but there will be cases when the user has not assigned a label yet -# # hence, the not_shown button is not shown but gets active -# # if the label has not been set yet -# labels.append('not_shown') -# for n, l in enumerate(labels): -# print n,l -# if n == 0: -# new_button = gtk.RadioButton(None, l) -# else: -# new_button = gtk.RadioButton(new_button, l) -# new_button.connect("toggled", self.label_button_clicked, l) -# if not l == 'not_shown': -# vbox.add(new_button) -# self.label_button_list.append(new_button) -# frame.add(vbox) -# hbox.pack_start(frame) -# # label section <-- end - - outer_frame.add(hbox) - self.vbox.pack_start(outer_frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - # --- ligand modeling --- - frame = gtk.Frame(label='Ligand Modeling') - self.hbox_for_modeling = gtk.HBox() - self.merge_ligand_button = gtk.Button(label="Merge Ligand") - self.place_ligand_here_button = gtk.Button(label="Place Ligand here") - self.hbox_for_modeling.add(self.place_ligand_here_button) - self.place_ligand_here_button.connect("clicked", self.place_ligand_here) - self.hbox_for_modeling.add(self.merge_ligand_button) - self.merge_ligand_button.connect("clicked", self.merge_ligand_into_protein) - frame.add(self.hbox_for_modeling) - self.vbox.pack_start(frame) - - # # --- ligand confidence --- - # self.cb_ligand_confidence = gtk.combo_box_new_text() - # self.cb_ligand_confidence.connect("changed", self.set_ligand_confidence) - # for citeria in self.ligand_confidence: - # self.cb_ligand_confidence.append_text(citeria) - # self.vbox.add(self.cb_ligand_confidence) - - - # --- refinement & options --- - self.hbox_for_refinement = gtk.HBox() - self.REFINEbutton = gtk.Button(label="Refine") - self.RefinementParamsButton = gtk.Button(label="refinement parameters") - self.REFINEbutton.connect("clicked", self.REFINE) - self.hbox_for_refinement.add(self.REFINEbutton) - self.RefinementParamsButton.connect("clicked", self.RefinementParams) - self.hbox_for_refinement.add(self.RefinementParamsButton) - self.vbox.add(self.hbox_for_refinement) - - # self.VALIDATEbutton = gtk.Button(label="validate structure") - # self.DEPOSITbutton = gtk.Button(label="prepare for deposition") - - - # need to put it here, because attributes within refinementProtocolCallback function - # are defined after checkbox is defined - self.refinementProtocolcheckbox.connect("toggled", self.refinementProtocolCallback) - - - # --- CANCEL button --- - self.CANCELbutton = gtk.Button(label="CANCEL") - self.CANCELbutton.connect("clicked", self.CANCEL) - self.vbox.add(self.CANCELbutton) - - self.window.add(self.vbox) - self.window.show_all() - - def CANCEL(self, widget): - self.window.destroy() - - def ChangeXtal(self, widget, data=None): - self.index = self.index + data - if self.index < 0: - self.index = 0 - if self.index >= len(self.Todo): - # self.index = len(self.Todo) - self.index = 0 - self.cb.set_active(self.index) - - def ChooseXtal(self, widget): - self.xtalID = str(widget.get_active_text()) - for n, item in enumerate(self.Todo): - if str(item[0]) == self.xtalID: - self.index = n - self.merge_ligand_button.set_sensitive(True) - self.place_ligand_here_button.set_sensitive(True) - -# self.ligand_site_name_value.set_label('-') -# self.ligand_inspect_confidence_value.set_label('-') -# self.ligand_inspect_interesting_value.set_label('-') -# self.ligand_inspect_comment_value.set_label('-') - - self.refresh_site_combobox() - self.db_dict_mainTable = {} - self.db_dict_panddaTable = {} - if str(self.Todo[self.index][0]) is not None: - self.compoundID = str(self.Todo[self.index][1]) - self.refinement_folder = str(self.Todo[self.index][4]) - self.refinement_outcome = str(self.Todo[self.index][5]) - self.label = self.db.get_label_of_sample(self.xtalID) -# self.update_label_radiobutton() - self.update_RefinementOutcome_radiobutton() - if self.xtalID not in self.siteDict: # i.e. we are not working with a PanDDA model - self.ligand_confidence = str(self.Todo[self.index][6]) - self.update_LigandConfidence_radiobutton() - self.label = self.db.get_label_of_sample(self.xtalID) -# self.update_label_radiobutton() - - self.RefreshData() - - def update_RefinementOutcome_radiobutton(self): - # updating dataset outcome radiobuttons - current_stage = 0 - for i, entry in enumerate(self.experiment_stage): - if entry[1].split()[0] == self.refinement_outcome.split()[0]: - current_stage = i - break - for i, button in enumerate(self.experiment_stage_button_list): - if i == current_stage: - button.set_active(True) - break - - def update_label_radiobutton(self): - found = False - for button in self.label_button_list: - if button.get_label() == self.label: - button.set_active(True) - found = True - if not found: - for button in self.label_button_list: - if button.get_label() == 'not_shown': - button.set_active(True) - break - - def update_LigandConfidence_radiobutton(self): - # updating ligand confidence radiobuttons - current_stage = 0 - for i, entry in enumerate(self.ligand_confidence_category): - print '--->', entry, self.ligand_confidence - try: - if entry.split()[0] == self.ligand_confidence.split()[0]: - current_stage = i - break - except IndexError: - pass - for i, button in enumerate(self.ligand_confidence_button_list): - if i == current_stage: - button.set_active(True) - break - - def refresh_site_combobox(self): - # reset self.pandda_index - self.pandda_index = -1 - # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever be 100 sites - for n in range(-1, 100): - self.cb_site.remove_text(0) - self.site_index = '0' - self.event_index = '0' - # only repopulate if site exists - if self.xtalID in self.siteDict: - for item in sorted(self.siteDict[self.xtalID]): - self.cb_site.append_text('site: {0!s} - event: {1!s}'.format(item[5], item[6])) - - def ChangeSite(self, widget, data=None): - if self.xtalID in self.siteDict: - self.pandda_index = self.pandda_index + data - if self.pandda_index < 0: - self.pandda_index = 0 - if self.pandda_index >= len(self.siteDict[self.xtalID]): - self.pandda_index = 0 - self.cb_site.set_active(self.pandda_index) - - def ChooseSite(self, widget): - tmp = str(widget.get_active_text()) - print self.siteDict - print self.site_index - self.site_index = tmp.split()[1] - self.event_index = tmp.split()[4] - for n, item in enumerate(self.siteDict[self.xtalID]): - if item[5] == self.site_index and item[6] == self.event_index: - self.pandda_index = n - self.RefreshSiteData() - - def RefreshSiteData(self): - - if self.pandda_index == -1: - self.merge_ligand_button.set_sensitive(True) - self.place_ligand_here_button.set_sensitive(True) - else: - self.merge_ligand_button.set_sensitive(False) - self.place_ligand_here_button.set_sensitive(False) - # and remove ligand molecule so that there is no temptation to merge it - if len(coot_utils_XChem.molecule_number_list()) > 0: - for imol in coot_utils_XChem.molecule_number_list(): - if self.compoundID + '.pdb' in coot.molecule_name(imol): - coot.close_molecule(imol) - - for w in self.label_button_list: - w.set_active(False) - - - print 'pandda index', self.pandda_index - self.spider_plot = self.siteDict[self.xtalID][self.pandda_index][4] - print 'new spider plot:', self.spider_plot - self.event_map = self.siteDict[self.xtalID][self.pandda_index][0] - print 'new event map:', self.event_map - self.ligand_confidence = str(self.siteDict[self.xtalID][self.pandda_index][7]) - self.update_LigandConfidence_radiobutton() - site_x = float(self.siteDict[self.xtalID][self.pandda_index][1]) - site_y = float(self.siteDict[self.xtalID][self.pandda_index][2]) - site_z = float(self.siteDict[self.xtalID][self.pandda_index][3]) - print 'new site coordinates:', site_x, site_y, site_z - coot.set_rotation_centre(site_x, site_y, site_z) - -# self.ligand_site_name_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][8])) -# self.ligand_inspect_confidence_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][9])) -# self.ligand_inspect_interesting_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][10])) -# self.ligand_inspect_comment_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][11])) - - self.spider_plot_data = self.db.get_db_pandda_dict_for_sample_and_site_and_event(self.xtalID, self.site_index, - self.event_index) - print '>>>>> spider plot data', self.spider_plot_data - self.ligandIDValue.set_label(self.spider_plot_data['PANDDA_site_ligand_id']) - try: - self.ligand_occupancyValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_occupancy']), 2))) - except ValueError: - self.ligand_occupancyValue.set_label('-') - - try: - self.ligand_BaverageValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_B_average']), 2))) - except ValueError: - self.ligand_BaverageValue.set_label('-') - - try: - self.ligand_BratioSurroundingsValue.set_label( - str(round(float(self.spider_plot_data['PANDDA_site_B_ratio_residue_surroundings']), 2))) - except ValueError: - self.ligand_BratioSurroundingsValue.set_label('-') - - try: - self.ligand_RSCCValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_RSCC']), 2))) - except ValueError: - self.ligand_RSCCValue.set_label('-') - - try: - self.ligand_rmsdValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_rmsd']), 2))) - except ValueError: - self.ligand_rmsdValue.set_label('-') - - try: - self.ligand_RSRValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_RSR']), 2))) - except ValueError: - self.ligand_RSRValue.set_label('-') - - try: - self.ligand_RSZDValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_RSZD']), 2))) - except ValueError: - self.ligand_RSZDValue.set_label('-') - - ######################################################################################### - # delete old Event MAPs - if len(coot_utils_XChem.molecule_number_list()) > 0: - for imol in coot_utils_XChem.molecule_number_list(): - if 'map.native.ccp4' in coot.molecule_name(imol): - coot.close_molecule(imol) - - ######################################################################################### - # Spider plot - # Note: refinement history was shown instead previously - if os.path.isfile(self.spider_plot): - spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) - else: - spider_plot_pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = spider_plot_pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - - ######################################################################################### - # check for PANDDAs EVENT maps - if os.path.isfile(self.event_map): - coot.set_colour_map_rotation_on_read_pdb(0) - coot.handle_read_ccp4_map((self.event_map), 0) - for imol in coot_utils_XChem.molecule_number_list(): - if self.event_map in coot.molecule_name(imol): - coot.set_contour_level_in_sigma(imol, 2) - # coot.set_contour_level_absolute(imol,0.5) - # coot.set_last_map_colour(0.4,0,0.4) - coot.set_last_map_colour(0.74, 0.44, 0.02) - - def experiment_stage_button_clicked(self, widget, data=None): - if data == '4 - CompChem ready' and self.refinementProtocol.startswith('pandda'): - print "==> XCE: removing refine.pdb and linking refine_.split.bound-state.pdb to refine.pdb" - os.chdir(os.path.join(self.project_directory,self.xtalID)) - if os.path.realpath('refine.pdb').replace('.pdb', '.split.bound-state.pdb'): - newPDB = os.path.realpath('refine.pdb').replace('.pdb', '.split.bound-state.pdb') - os.system('/bin/rm refine.pdb') - os.system('ln -s .%s refine.pdb' %newPDB.replace(os.getcwd(),'')) - self.refinementProtocolcheckbox.set_active(False) - self.refinementProtocol = 'refmac' - else: - print '==> XCE ERROR: cannot find refine.output.bound-state.pdb' - pass - self.db_dict_mainTable['RefinementOutcome'] = data - print '==> XCE: setting Refinement Outcome for ' + self.xtalID + ' to ' + str( - data) + ' in mainTable of datasource' - # self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - self.db.create_or_remove_missing_records_in_depositTable(self.xce_logfile, self.xtalID, 'ligand_bound', - self.db_dict_mainTable) - - - def ligand_confidence_button_clicked(self, widget, data=None): - print 'PANDDA_index', self.pandda_index - if self.pandda_index == -1: - self.db_dict_mainTable['RefinementLigandConfidence'] = data - print '==> XCE: setting Ligand Confidence for ' + self.xtalID + ' to ' + str( - data) + ' in mainTable of datasource' - self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - self.Todo[self.index][6] = data - else: - self.db_dict_panddaTable['PANDDA_site_confidence'] = data - print '==> XCE: setting Ligand Confidence for ' + self.xtalID + ' (site=' + str( - self.site_index) + ', event=' + str(self.event_index) + ') to ' + str( - data) + ' in panddaTable of datasource' - self.db.update_site_event_panddaTable(self.xtalID, self.site_index, self.event_index, - self.db_dict_panddaTable) - self.siteDict[self.xtalID][self.pandda_index][7] = data - -# def update_label(self, widget): -# print '\n\n\n>>>>>>>>>>>>>>>>>>>>>>>>' -# # widget.pressed() -# for w in self.label_button_list: -# print w.get_label(), w.get_active() -# if w != widget: -# w.set_active(False) -# print '<<<<<<<<<<<<<<<<<<<<<<<<<<' -# self.db_dict_mainTable['label'] = widget.get_label() -# print '==> XCE: setting label for ' + self.xtalID + ' to ' + str( -# widget.get_label()) + ' in mainTable of datasource' -# self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - -# def label_button_clicked(self, widget, data=None): -# print '............',data -# if data == 'not_shown': -# self.db.execute_statement("update mainTable set label=Null where CrystalName = '%s'" %self.xtalID) -# else: -# self.db_dict_mainTable['label'] = data -# print '==> XCE: setting label for ' + self.xtalID + ' to ' + str(data) + ' in mainTable of datasource' -# self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - - def RefreshData(self): - # reset spider plot image - spider_plot_pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = spider_plot_pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - - # reset ground state mean map - self.ground_state_mean_map = '' - self.ground_state_mean_map_button.set_sensitive(False) - self.ground_state_mean_map_button.set_label('Show ground state mean map') - if os.path.isfile( - os.path.join(self.project_directory, self.xtalID, self.xtalID + '-ground-state-mean-map.native.ccp4')): - self.ground_state_mean_map_button.set_sensitive(True) - self.ground_state_mean_map = os.path.join(self.project_directory, self.xtalID, - self.xtalID + '-ground-state-mean-map.native.ccp4') - - # initialize Refinement library - self.Refine = XChemRefine.Refine(self.project_directory, self.xtalID, self.compoundID, self.data_source) - self.Serial = XChemRefine.GetSerial(self.project_directory, self.xtalID) - self.panddaSerial = panddaSerial = m = (4 - len(str(self.Serial))) * '0' + str(self.Serial) - # self.Serial=self.Refine.GetSerial() - if self.Serial == 1: - # i.e. no refinement has been done; data is probably straight out of dimple - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.pdb_style)): - print '==> XCE: updating quality indicators in data source for ' + self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID, self.data_source, - os.path.join(self.project_directory, self.xtalID, - self.pdb_style)) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID, self.data_source, - '') # '' because file does not exist - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'init.pdb')): - print '==> XCE: updating quality indicators in data source for ' + self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID, self.data_source, - os.path.join(self.project_directory, self.xtalID, - 'init.pdb')) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID, self.data_source, - '') # '' because file does not exist - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'dimple.pdb')): - print '==> XCE: updating quality indicators in data source for ' + self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID, self.data_source, - os.path.join(self.project_directory, self.xtalID, - 'dimple.pdb')) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID, self.data_source, - '') # '' because file does not exist - - # all this information is now updated in the datasource after each refinement cycle - self.QualityIndicators = self.db.get_db_dict_for_sample(self.xtalID) - - ######################################################################################### - # history - # if the structure was previously refined, try to read the parameters - # self.hbox_for_info_graphics.remove(self.canvas) - if self.Serial > 1: - self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) - print '==> REFMAC params:', self.RefmacParams - # refinement_cycle,Rfree,Rcryst=self.Refine.GetRefinementHistory() - # self.canvas = FigureCanvas(self.update_plot(refinement_cycle,Rfree,Rcryst)) - # else: - # self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) # a gtk.DrawingArea - # self.canvas.set_size_request(190, 190) - # self.hbox_for_info_graphics.add(self.canvas) - # self.canvas.show() - - ######################################################################################### - # update pdb & maps - - ######################################################################################### - # delete old PDB and MAP files - # - get a list of all molecules which are currently opened in COOT - # - remove all molecules/ maps before loading a new set - if len(coot_utils_XChem.molecule_number_list()) > 0: - for item in coot_utils_XChem.molecule_number_list(): - coot.close_molecule(item) - - ######################################################################################### - # read new PDB files - # read protein molecule after ligand so that this one is the active molecule - coot.set_nomenclature_errors_on_read("ignore") - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.compoundID + '.pdb')): - coot.set_colour_map_rotation_on_read_pdb(0) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, self.compoundID + '.pdb'), 0) - self.mol_dict['ligand'] = imol - coot.read_cif_dictionary(os.path.join(self.project_directory, self.xtalID, self.compoundID + '.cif')) - if not os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.pdb_style)): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - - if self.refinementProtocol.startswith('pandda'): - print '=> XCE: looking for ground-state model', os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.ground-state.pdb') - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', '') + '.split.ground-state.pdb')): - print '=> XCE: found ground-state model' - os.chdir(os.path.join(self.project_directory, self.xtalID)) - coot.set_colour_map_rotation_on_read_pdb(0) - try: - color_wheel_rotation = 160 / float(imol + 2) - except UnboundLocalError: - color_wheel_rotation = 80 - coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) - imol = coot.handle_read_draw_molecule_with_recentre(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.ground-state.pdb'), - 0) - coot.set_colour_by_molecule(imol) - coot.set_mol_active(imol, 0) - else: - print '=> XCE - ERROR: cannot find ground-state model' - print '=> XCE: looking for bound-state model', os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.bound-state.pdb') - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', '') + '.split.bound-state.pdb')): - print '=> XCE: found bound-state model' - os.chdir(os.path.join(self.project_directory, self.xtalID)) - coot.set_colour_map_rotation_on_read_pdb(0) - color_wheel_rotation = 21 / float(imol + 2) - coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) - imol = coot.handle_read_draw_molecule_with_recentre(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.bound-state.pdb'), - 0) - self.mol_dict['protein'] = imol - else: - print '=> XCE - ERROR: cannot find bound-state model' - print '=> XCE: moving to next crystal...' - self.go_to_next_xtal() - else: - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.pdb_style)): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, self.pdb_style), 0) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'init.pdb')): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, 'init.pdb'), 0) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'dimple.pdb')): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, 'dimple.pdb'), 0) - else: - self.go_to_next_xtal() - self.mol_dict['protein'] = imol - - # read any one event map if present - for event_map in glob.glob( - os.path.join(self.project_directory, self.xtalID, self.xtalID + '-event_*.native.ccp4')): - coot.handle_read_ccp4_map((event_map), 0) - coot.set_contour_level_in_sigma(imol, 2) - coot.set_last_map_colour(0.74, 0.44, 0.02) - break - - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith( - self.pdb_style.replace('.pdb', '') + '.split.bound-state.pdb') or coot.molecule_name( - item).endswith(self.pdb_style): - coot.set_show_symmetry_master(1) # master switch to show symmetry molecules - coot.set_show_symmetry_molecule(item, 1) # show symm for model - - ######################################################################################### - # read fofc maps - # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map - # read 2fofc map last so that one can change its contour level - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, '2fofc.map')): - coot.set_colour_map_rotation_on_read_pdb(0) - coot.set_default_initial_contour_level_for_difference_map(3) - coot.handle_read_ccp4_map(os.path.join(self.project_directory, self.xtalID, 'fofc.map'), 1) - coot.set_default_initial_contour_level_for_map(1) - coot.handle_read_ccp4_map(os.path.join(self.project_directory, self.xtalID, '2fofc.map'), 0) - coot.set_last_map_colour(0, 0, 1) - else: - # try to open mtz file with same name as pdb file - coot.set_default_initial_contour_level_for_map(1) - # if not os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.mtz_style)): - # os.chdir(os.path.join(self.project_directory,self.xtalID)) - # if not os.path.isfile('REFINEMENT_IN_PROGRESS'): - # if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.xtalID+'-pandda-input.mtz')): - # os.symlink(self.xtalID+'-pandda-input.mtz',self.mtz_style) - # elif os.path.isfile(os.path.join(self.project_directory,self.xtalID,'dimple.mtz')): - # os.symlink('dimple.mtz',self.mtz_style) - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.mtz_style)): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory, self.xtalID, self.mtz_style)) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'init.mtz')): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory, self.xtalID, 'init.mtz')) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'dimple.mtz')): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory, self.xtalID, 'dimple.mtz')) - - ######################################################################################### - # update Quality Indicator table - try: - self.RRfreeValue.set_label(str(round(float(self.QualityIndicators['RefinementRcryst']), 3)) + ' / ' + str( - round(float(self.QualityIndicators['RefinementRfree']), 3))) - except ValueError: - self.RRfreeValue.set_label('-') - - try: - self.RRfreeBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementRfreeTraficLight'])) - except ValueError: - pass - self.ResolutionValue.set_label(self.QualityIndicators['RefinementResolution']) - try: - self.ResolutionBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementResolutionTL'])) - except ValueError: - pass - self.MolprobityScoreValue.set_label(self.QualityIndicators['RefinementMolProbityScore']) - try: - self.MolprobityScoreBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse( - self.QualityIndicators['RefinementMolProbityScoreTL'])) - except ValueError: - pass - self.RamachandranOutliersValue.set_label(self.QualityIndicators['RefinementRamachandranOutliers']) - try: - self.RamachandranOutliersBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse( - self.QualityIndicators['RefinementRamachandranOutliersTL'])) - except ValueError: - pass - self.RamachandranFavoredValue.set_label(self.QualityIndicators['RefinementRamachandranFavored']) - try: - self.RamachandranFavoredBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse( - self.QualityIndicators['RefinementRamachandranFavoredTL'])) - except ValueError: - pass - self.rmsdBondsValue.set_label(self.QualityIndicators['RefinementRmsdBonds']) - try: - self.rmsdBondsBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementRmsdBondsTL'])) - except ValueError: - pass - self.rmsdAnglesValue.set_label(self.QualityIndicators['RefinementRmsdAngles']) - try: - self.rmsdAnglesBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementRmsdAnglesTL'])) - except ValueError: - pass - self.MatrixWeightValue.set_label(self.QualityIndicators['RefinementMatrixWeight']) - - try: - pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(self.project_directory, self.xtalID, self.compoundID + '.png')) - except gobject.GError: - pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_COMPOUND_IMAGE_AVAILABLE.png')) - self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.image.set_from_pixbuf(self.pic) - - def go_to_next_xtal(self): - self.index += 1 - if self.index >= len(self.Todo): - self.index = len(self.Todo) - self.cb.set_active(self.index) - - def REFINE(self, widget): - - # ####################################################### - # if not os.path.isdir(os.path.join(self.project_directory,self.xtalID,'cootOut')): - # os.mkdir(os.path.join(self.project_directory,self.xtalID,'cootOut')) - # # create folder for new refinement cycle - # os.mkdir(os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial))) - # - # ####################################################### - # # write PDB file - # # now take protein pdb file and write it to newly create Refine_ folder - # # note: the user has to make sure that the ligand file was merged into main file - # for item in coot_utils_XChem.molecule_number_list(): - # if coot.molecule_name(item).endswith(self.pdb_style.replace('.pdb','')+'.split.bound-state.pdb') or coot.molecule_name(item).endswith(self.pdb_style): - # coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial),'refine.modified.pdb')) - # break - # elif coot.molecule_name(item).endswith('dimple.pdb'): - # coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial),'refine.modified.pdb')) - # break - # - - ####################################################### - if self.refinementProtocol.startswith('pandda'): - - ####################################################### - if not os.path.isdir(os.path.join(self.project_directory, self.xtalID, 'cootOut')): - os.mkdir(os.path.join(self.project_directory, self.xtalID, 'cootOut')) - # create folder for new refinement cycle - try: - os.mkdir(os.path.join(self.project_directory, self.xtalID, 'cootOut', 'Refine_' + str(self.Serial))) - except OSError: - print '==> XCE: WARNING -> folder exists; will overwrite contents!' - - ####################################################### - # write PDB file - # now take protein pdb file and write it to newly create Refine_ folder - # note: the user has to make sure that the ligand file was merged into main file - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith( - self.pdb_style.replace('.pdb', '') + '.split.bound-state.pdb') or coot.molecule_name( - item).endswith(self.pdb_style): - coot.write_pdb_file(item, os.path.join(self.project_directory, self.xtalID, 'cootOut', - 'Refine_' + str(self.Serial), 'refine.modified.pdb')) - break - # elif coot.molecule_name(item).endswith('dimple.pdb'): - # coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial),'refine.modified.pdb')) - # break - - XChemRefine.panddaRefine(self.project_directory, self.xtalID, self.compoundID, - self.data_source).RunQuickRefine(self.Serial, self.RefmacParams, - self.external_software, self.xce_logfile, - self.refinementProtocol) - else: - ####################################################### - # create folder for new refinement cycle and check if free.mtz exists - if not os.path.isdir(os.path.join(self.project_directory, self.xtalID)): - os.mkdir(os.path.join(self.project_directory, self.xtalID)) - if not os.path.isdir(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial))): - os.mkdir(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial))) - - ####################################################### - # write PDB file - # now take protein pdb file and write it to newly create Refine_ folder - # note: the user has to make sure that the ligand file was merged into main file - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith(self.pdb_style): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial), - 'in.pdb')) - break - elif coot.molecule_name(item).endswith('refine.split.bound-state.pdb'): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, - 'Refine_' + str(self.Serial), - 'in.pdb')) - break - elif coot.molecule_name(item).endswith('init.pdb'): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial), - 'in.pdb')) - break - elif coot.molecule_name(item).endswith('dimple.pdb'): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial), - 'in.pdb')) - break - - self.Refine.RunRefmac(self.Serial, self.RefmacParams, self.external_software, self.xce_logfile) - - self.index += 1 - if self.index >= len(self.Todo): - # self.index = len(self.Todo) - self.index = 0 - self.cb.set_active(self.index) - - def RefinementParams(self, widget): - print '\n==> XCE: changing refinement parameters' - self.RefmacParams = XChemRefine.RefineParams(self.project_directory, self.xtalID, self.compoundID, - self.data_source).RefmacRefinementParams(self.RefmacParams) - - def set_selection_mode(self, widget): - self.selection_mode = widget.get_active_text() - - def get_samples_to_look_at(self, widget): - if self.selection_mode == '': - self.status_label.set_text('select model stage') - return - self.status_label.set_text('checking datasource for samples... ') - # first remove old samples if present - if len(self.Todo) != 0: - for n, item in enumerate(self.Todo): - self.cb.remove_text(0) - self.Todo = [] - self.siteDict = {} - self.Todo, self.siteDict = self.db.get_todoList_for_coot(self.selection_mode) -# self.status_label.set_text('found {0!s} samples'.format(len(self.Todo))) - # refresh sample CB - for item in sorted(self.Todo): - self.cb.append_text('{0!s}'.format(item[0])) - if self.siteDict == {}: - self.cb_site.set_sensitive(False) - self.PREVbuttonSite.set_sensitive(False) - self.NEXTbuttonSite.set_sensitive(False) - else: - self.cb_site.set_sensitive(True) - self.PREVbuttonSite.set_sensitive(True) - self.NEXTbuttonSite.set_sensitive(True) - print '===========>',self.cb_select_samples.get_active_text() - if int(self.cb_select_samples.get_active_text().split()[0]) > 3: - print '==> XCE: sorry cannot change refinement protocol since you are at a stage when we refine the ligand bound state only' - self.refinementProtocol = 'refmac' - self.refinementProtocolcheckbox.set_active(False) - - - def update_plot(self, refinement_cycle, Rfree, Rcryst): - fig = Figure(figsize=(2, 2), dpi=50) - Plot = fig.add_subplot(111) - Plot.set_ylim([0, max(Rcryst + Rfree)]) - Plot.set_xlabel('Refinement Cycle', fontsize=12) - Plot.plot(refinement_cycle, Rfree, label='Rfree', linewidth=2) - Plot.plot(refinement_cycle, Rcryst, label='Rcryst', linewidth=2) - Plot.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, - ncol=2, mode="expand", borderaxespad=0., fontsize=12) - return fig - - def place_ligand_here(self, widget): - print '===> XCE: moving ligand to pointer' - # coot.move_molecule_here() - print 'LIGAND: ', self.mol_dict['ligand'] - coot_utils_XChem.move_molecule_here(self.mol_dict['ligand']) - - def merge_ligand_into_protein(self, widget): - print '===> XCE: merge ligand into protein structure' - # merge_molecules(list(imols), imol) e.g. merge_molecules([1],0) - coot.merge_molecules_py([self.mol_dict['ligand']], self.mol_dict['protein']) - print '===> XCE: deleting ligand molecule' - coot.close_molecule(self.mol_dict['ligand']) - - def show_molprobity_to_do(self, widget): - print self.panddaSerial - AdjPanddaSerial = (4 - len(str(self.Serial))) * '0' + str(int(self.panddaSerial) - 1) - print os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.panddaSerial), - 'molprobity_coot.py') - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial - 1), - 'molprobity_coot.py')): - print '==> XCE: running MolProbity Summary for', self.xtalID - coot.run_script(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial - 1), - 'molprobity_coot.py')) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(AdjPanddaSerial), - 'molprobity_coot.py')): - print '==> XCE: running MolProbity Summary for', self.xtalID - coot.run_script(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(AdjPanddaSerial), - 'molprobity_coot.py')) - else: - print '==> XCE: cannot find ' + os.path.join(self.project_directory, self.xtalID, - 'Refine_' + str(self.Serial - 1), 'molprobity_coot.py') - - def refinementProtocolCallback(self, widget): - if widget.get_active(): - if self.refinementProtocolcheckbox.get_active(): - self.refinementProtocol = 'pandda_phenix' - else: - self.refinementProtocol = 'pandda_refmac' - self.PREVbuttonSite.set_sensitive(True) - self.NEXTbuttonSite.set_sensitive(True) - else: - self.refinementProtocolcheckbox.set_active(False) - self.refinementProtocol = 'refmac' - self.PREVbuttonSite.set_sensitive(False) - self.NEXTbuttonSite.set_sensitive(False) - print self.refinementProtocol - - def refinementProgramCallback(self, widget): - if widget.get_active(): - if self.refinementProtocolcheckbox.get_active(): - self.refinementProtocol = 'pandda_phenix' - self.RefinementParamsButton.set_sensitive(False) - else: - self.refinementProgramcheckbox.set_active(False) - self.refinementProtocol = 'refmac' - else: - self.RefinementParamsButton.set_sensitive(True) - if self.refinementProtocolcheckbox.get_active(): - self.refinementProtocol = 'pandda_refmac' - else: - self.refinementProtocol = 'refmac' - if int(self.refinement_outcome.split()[0]) > 3: - print '==> XCE: sorry cannot change refinement protocol since you are at a stage when we refine the ligand bound state only' - self.refinementProtocol = 'refmac' - self.refinementProtocolcheckbox.set_active(False) - print self.refinementProtocol - - def show_ground_state_mean_map(self, widget): - if widget.get_label().startswith('Show'): - loaded = False - for imol in coot_utils_XChem.molecule_number_list(): - if 'ground-state-mean-map' in coot.molecule_name(imol): - coot.set_map_displayed(imol, 1) - loaded = True - break - if not loaded: - coot.set_default_initial_contour_level_for_map(1) - coot.handle_read_ccp4_map(self.ground_state_mean_map, 0) - coot.set_last_map_colour(0.6, 0.6, 0) - widget.set_label('Undisplay ground state mean map') - else: - for imol in coot_utils_XChem.molecule_number_list(): - if 'ground-state-mean-map' in coot.molecule_name(imol): - coot.set_map_displayed(imol, 0) - widget.set_label('Show ground state mean map') - - def reset_occupancy(self): - self.Logfile.warning('==> COOT: trying to set occupancies of all residues to 1.0') - if self.refinementProtocol.startswith('pandda'): - self.Logfile.warning('==> COOT: you cannot reset occupancies while working in PanDDA refine mode') - else: - for imol in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(imol).endswith(self.pdb_style) or \ - coot.molecule_name(imol).endswith('refine.split.bound-state.pdb') or \ - coot.molecule_name(imol).endswith('ini.pdb') or \ - coot.molecule_name(imol).endswith('dimple.pdb'): - self.Logfile.warning('==> COOT: setting occupancies of all protein residues in %s to 1.0' %coot.molecule_name(imol)) -# coot.fill_occupancy_residue_range(imol,"A",1,10000) - chains = chain_ids(imol) - resiDict = {} - for chain in chains: - resiDict[chain] = residues_in_chain(imol, chain) - amino_acids = XChemUtils.pdbtools(coot.molecule_name(imol)).amino_acids() - - resetDict = {} - for chain in resiDict: - residRange = [] - resid_prev = -1000 - n_res = 0 - for resid in resiDict[chain]: - if residue_name(imol,chain,resid[1],'') in amino_acids: - n_res += 1 - counter = 0 - for n,resid in enumerate(resiDict[chain]): - if residue_name(imol,chain,resid[1],'') in amino_acids: - counter += 1 - if chain not in resetDict: - resetDict[chain] = None - if resid[1] != resid_prev + 1: - if resid_prev != -1000: - residRange.append([start,resid_prev]) - start = resid[1] - resid_prev = resid[1] - if counter == n_res: - residRange.append([start,resid[1]]) - if chain in resetDict: - resetDict[chain] = residRange - for chain in resetDict: - for resid_range in resetDict[chain]: - print 'setting occupancy to 1: ->',chain,resid_range[0],resid_range[1] - coot.fill_occupancy_residue_range(imol,chain,resid_range[0],resid_range[1]) - - - -# -# -# print residues_in_chain(imol, chain) -# for residue in residues_in_chain(imol, chain): -# print residue - - -if __name__ == '__main__': - GUI().StartGUI() diff --git a/lib/XChemCootNew.py b/lib/XChemCootNew.py deleted file mode 100755 index 460b3bc5..00000000 --- a/lib/XChemCootNew.py +++ /dev/null @@ -1,1662 +0,0 @@ -# last edited: 08/08/2017 - 15:00 - -import gobject -import sys -import os -import pickle -import glob - -from matplotlib.figure import Figure - -# from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas - -# XCE libraries -sys.path.append(os.getenv('XChemExplorer_DIR') + '/lib') -import XChemDB -import XChemRefine -import XChemUtils -import XChemLog - -# libraries from COOT -import pygtk, gtk, pango -import coot - -# had to adapt the original coot_utils.py file -# otherwise unable to import the original file without complaints about missing modules etc. -# modified file is now in $XChemExplorer_DIR/lib -import coot_utils_XChem - - -class GUI(object): - """ - main class which opens the actual GUI - """ - - def __init__(self): - - ########################################################################################### - # read in settings file from XChemExplorer to set the relevant paths - self.settings = pickle.load(open(".xce_settings.pkl", "rb")) - - remote_qsub_submission = self.settings['remote_qsub'] - self.database_directory = self.settings['database_directory'] - self.xce_logfile = self.settings['xce_logfile'] - self.Logfile = XChemLog.updateLog(self.xce_logfile) - self.Logfile.insert('==> COOT: starting coot plugin...') - self.data_source = self.settings['data_source'] - self.db = XChemDB.data_source(self.data_source) - - print self.settings - - # checking for external software packages - self.external_software = XChemUtils.external_software(self.xce_logfile).check() - self.external_software['qsub_remote'] = remote_qsub_submission - - self.selection_criteria = ['0 - All Datasets', - '1 - Analysis Pending', - '2 - PANDDA model', - '3 - In Refinement', - '4 - CompChem ready', - '5 - Deposition ready', - '6 - Deposited', - '7 - Analysed & Rejected'] - - self.experiment_stage = [['Review PANDDA export', '2 - PANDDA model', 65000, 0, 0], - ['In Refinement', '3 - In Refinement', 65000, 0, 0], - ['Comp Chem Ready!', '4 - CompChem ready', 65000, 0, 0], - ['Ready for Deposition!', '5 - Deposition ready', 65000, 0, 0], - ['In PDB', '6 - Deposited', 65000, 0, 0], - ['Analysed & Rejected', '7 - Analysed & Rejected', 65000, 0, 0]] - - self.ligand_confidence_category = ['0 - no ligand present', - '1 - Low Confidence', - '2 - Correct ligand, weak density', - '3 - Clear density, unexpected ligand', - '4 - High Confidence'] - - self.ligand_site_information = self.db.get_list_of_pandda_sites_for_coot() - - # this decides which samples will be looked at - self.selection_mode = '' - # self.selected_site='' - self.pandda_index = -1 # refers to the number of sites - self.site_index = '0' - self.event_index = '0' - - # the Folder is kind of a legacy thing because my inital idea was to have separate folders - # for Data Processing and Refinement - self.project_directory = self.settings['initial_model_directory'] - self.Serial = 0 - self.panddaSerial = 0 - self.Refine = None - self.index = -1 - self.Todo = [] - self.siteDict = {} - - self.xtalID = '' - self.compoundID = '' - self.ground_state_mean_map = '' - self.spider_plot = '' - self.ligand_confidence = '' - self.refinement_folder = '' - self.refinementProtocol = 'pandda_refmac' - # self.datasetOutcome='' - - self.pdb_style = 'refine.pdb' - self.mtz_style = 'refine.mtz' - - self.covLink = ['X', 'X', 'X', 'X'] - self.covLinkObject = coot.new_generic_object_number("covalent bond") - self.covLinkAtomSpec = None - - self.label = None - - # stores imol of currently loaded molecules and maps - self.mol_dict = {'protein': -1, - 'ligand': -1, - '2fofc': -1, - 'fofc': -1, - 'event': -1, - 'ligand_stereo': []} - - # two dictionaries which are flushed when a new crystal is loaded - # and which contain information to update the data source if necessary - self.db_dict_mainTable = {} - self.db_dict_panddaTable = {} - - self.label_button_list = [] - - - ########################################################################################### - # some COOT settings - coot.set_map_radius(17) - coot.set_colour_map_rotation_for_map(0) - # coot.set_colour_map_rotation_on_read_pdb_flag(21) - - self.QualityIndicators = {'RefinementRcryst': '-', - 'RefinementRfree': '-', - 'RefinementRfreeTraficLight': 'gray', - 'RefinementResolution': '-', - 'RefinementResolutionTL': 'gray', - 'RefinementMolProbityScore': '-', - 'RefinementMolProbityScoreTL': 'gray', - 'RefinementRamachandranOutliers': '-', - 'RefinementRamachandranOutliersTL': 'gray', - 'RefinementRamachandranFavored': '-', - 'RefinementRamachandranFavoredTL': 'gray', - 'RefinementRmsdBonds': '-', - 'RefinementRmsdBondsTL': 'gray', - 'RefinementRmsdAngles': '-', - 'RefinementRmsdAnglesTL': 'gray', - 'RefinementMatrixWeight': '-'} - - self.spider_plot_data = {'PANDDA_site_ligand_id': '-', - 'PANDDA_site_occupancy': '-', - 'PANDDA_site_B_average': '-', - 'PANDDA_site_B_ratio_residue_surroundings': '-', - 'PANDDA_site_RSCC': '-', - 'PANDDA_site_rmsd': '-', - 'PANDDA_site_RSR': '-', - 'PANDDA_site_RSZD': '-'} - - # default refmac parameters - self.RefmacParams = {'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': ''} - - def StartGUI(self): - - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_default_size(400, 800) - self.window.set_title("XChemExplorer") - self.vbox = gtk.VBox() # this is the main container - - ################################################################################# - # --- Sample Selection --- - # self.vbox.add(gtk.Label('Select Samples')) - - frame = gtk.Frame(label='Select Samples') - self.hbox_select_samples = gtk.HBox() - # vbox=gtk.VBox() - - self.cb_select_samples = gtk.combo_box_new_text() - self.cb_select_samples.connect("changed", self.set_selection_mode) - for citeria in self.selection_criteria: - self.cb_select_samples.append_text(citeria) - self.hbox_select_samples.add(self.cb_select_samples) - - # self.cb_select_sites = gtk.combo_box_new_text() - # self.cb_select_sites.connect("changed", self.set_site) - # for site in self.ligand_site_information: - # self.cb_select_sites.append_text(str(site[0])+' - '+str(site[1])) - # self.hbox_select_samples.add(self.cb_select_sites) - - self.select_samples_button = gtk.Button(label="GO") - self.select_samples_button.connect("clicked", self.get_samples_to_look_at) - self.hbox_select_samples.add(self.select_samples_button) - frame.add(self.hbox_select_samples) - self.vbox.pack_start(frame) - - ################################################################################# - # --- status window --- - frame = gtk.Frame() - self.status_label = gtk.Label() - frame.add(self.status_label) - self.vbox.pack_start(frame) - - ################################################################################# - # --- refinement protocol --- - frame = gtk.Frame() - self.refinementProtocolcheckbox = gtk.CheckButton('PanDDA model refinement)') - # callback is defined later -# self.refinementProtocolcheckbox.connect("toggled", self.refinementProtocolCallback) - self.refinementProtocolcheckbox.set_active(True) - frame.add(self.refinementProtocolcheckbox) - self.vbox.pack_start(frame) - - ################################################################################# - # --- refinement program --- -# frame = gtk.Frame() -# self.refinementProgramcheckbox = gtk.CheckButton('use PHENIX for giant.quick_refine') -# self.refinementProgramcheckbox.connect("toggled", self.refinementProgramCallback) -# self.refinementProgramcheckbox.set_active(False) -# frame.add(self.refinementProgramcheckbox) -# self.vbox.pack_start(frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- Refinement Statistics --- - # next comes a section which displays some global quality indicators - # a combination of labels and textview widgets, arranged in a table - - RRfreeLabel_frame = gtk.Frame() - self.RRfreeLabel = gtk.Label('R/Rfree') - RRfreeLabel_frame.add(self.RRfreeLabel) - self.RRfreeValue = gtk.Label( - self.QualityIndicators['RefinementRcryst'] + '/' + self.QualityIndicators['RefinementRfree']) - RRfreeBox_frame = gtk.Frame() - self.RRfreeBox = gtk.EventBox() - self.RRfreeBox.add(self.RRfreeValue) - RRfreeBox_frame.add(self.RRfreeBox) - - ResolutionLabel_frame = gtk.Frame() - self.ResolutionLabel = gtk.Label('Resolution') - ResolutionLabel_frame.add(self.ResolutionLabel) - self.ResolutionValue = gtk.Label(self.QualityIndicators['RefinementResolution']) - ResolutionBox_frame = gtk.Frame() - self.ResolutionBox = gtk.EventBox() - self.ResolutionBox.add(self.ResolutionValue) - ResolutionBox_frame.add(self.ResolutionBox) - - MolprobityScoreLabel_frame = gtk.Frame() - self.MolprobityScoreLabel = gtk.Label('MolprobityScore') - MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) - self.MolprobityScoreValue = gtk.Label(self.QualityIndicators['RefinementMolProbityScore']) - MolprobityScoreBox_frame = gtk.Frame() - self.MolprobityScoreBox = gtk.EventBox() - self.MolprobityScoreBox.add(self.MolprobityScoreValue) - MolprobityScoreBox_frame.add(self.MolprobityScoreBox) - - RamachandranOutliersLabel_frame = gtk.Frame() - self.RamachandranOutliersLabel = gtk.Label('Rama Outliers') - RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) - self.RamachandranOutliersValue = gtk.Label(self.QualityIndicators['RefinementRamachandranOutliers']) - RamachandranOutliersBox_frame = gtk.Frame() - self.RamachandranOutliersBox = gtk.EventBox() - self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) - RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) - - RamachandranFavoredLabel_frame = gtk.Frame() - self.RamachandranFavoredLabel = gtk.Label('Rama Favored') - RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) - self.RamachandranFavoredValue = gtk.Label(self.QualityIndicators['RefinementRamachandranFavored']) - RamachandranFavoredBox_frame = gtk.Frame() - self.RamachandranFavoredBox = gtk.EventBox() - self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) - RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) - - rmsdBondsLabel_frame = gtk.Frame() - self.rmsdBondsLabel = gtk.Label('rmsd(Bonds)') - rmsdBondsLabel_frame.add(self.rmsdBondsLabel) - self.rmsdBondsValue = gtk.Label(self.QualityIndicators['RefinementRmsdBonds']) - rmsdBondsBox_frame = gtk.Frame() - self.rmsdBondsBox = gtk.EventBox() - self.rmsdBondsBox.add(self.rmsdBondsValue) - rmsdBondsBox_frame.add(self.rmsdBondsBox) - - rmsdAnglesLabel_frame = gtk.Frame() - self.rmsdAnglesLabel = gtk.Label('rmsd(Angles)') - rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) - self.rmsdAnglesValue = gtk.Label(self.QualityIndicators['RefinementRmsdAngles']) - rmsdAnglesBox_frame = gtk.Frame() - self.rmsdAnglesBox = gtk.EventBox() - self.rmsdAnglesBox.add(self.rmsdAnglesValue) - rmsdAnglesBox_frame.add(self.rmsdAnglesBox) - - MatrixWeightLabel_frame = gtk.Frame() - self.MatrixWeightLabel = gtk.Label('Matrix Weight') - MatrixWeightLabel_frame.add(self.MatrixWeightLabel) - self.MatrixWeightValue = gtk.Label(self.QualityIndicators['RefinementMatrixWeight']) - MatrixWeightBox_frame = gtk.Frame() - self.MatrixWeightBox = gtk.EventBox() - self.MatrixWeightBox.add(self.MatrixWeightValue) - MatrixWeightBox_frame.add(self.MatrixWeightBox) - - ligandIDLabel_frame = gtk.Frame() - self.ligandIDLabel = gtk.Label('Ligand ID') - ligandIDLabel_frame.add(self.ligandIDLabel) - self.ligandIDValue = gtk.Label(self.spider_plot_data['PANDDA_site_ligand_id']) - ligandIDBox_frame = gtk.Frame() - self.ligandIDBox = gtk.EventBox() - self.ligandIDBox.add(self.ligandIDValue) - ligandIDBox_frame.add(self.ligandIDBox) - - ligand_occupancyLabel_frame = gtk.Frame() - self.ligand_occupancyLabel = gtk.Label('occupancy') - ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) - self.ligand_occupancyValue = gtk.Label(self.spider_plot_data['PANDDA_site_occupancy']) - ligand_occupancyBox_frame = gtk.Frame() - self.ligand_occupancyBox = gtk.EventBox() - self.ligand_occupancyBox.add(self.ligand_occupancyValue) - ligand_occupancyBox_frame.add(self.ligand_occupancyBox) - - ligand_BaverageLabel_frame = gtk.Frame() - self.ligand_BaverageLabel = gtk.Label('B average') - ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) - self.ligand_BaverageValue = gtk.Label(self.spider_plot_data['PANDDA_site_B_average']) - ligand_BaverageBox_frame = gtk.Frame() - self.ligand_BaverageBox = gtk.EventBox() - self.ligand_BaverageBox.add(self.ligand_BaverageValue) - ligand_BaverageBox_frame.add(self.ligand_BaverageBox) - - ligand_BratioSurroundingsLabel_frame = gtk.Frame() - self.ligand_BratioSurroundingsLabel = gtk.Label('B ratio') - ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) - self.ligand_BratioSurroundingsValue = gtk.Label( - self.spider_plot_data['PANDDA_site_B_ratio_residue_surroundings']) - ligand_BratioSurroundingsBox_frame = gtk.Frame() - self.ligand_BratioSurroundingsBox = gtk.EventBox() - self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) - ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) - - ligand_RSCCLabel_frame = gtk.Frame() - self.ligand_RSCCLabel = gtk.Label('RSCC') - ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) - self.ligand_RSCCValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSCC']) - ligand_RSCCBox_frame = gtk.Frame() - self.ligand_RSCCBox = gtk.EventBox() - self.ligand_RSCCBox.add(self.ligand_RSCCValue) - ligand_RSCCBox_frame.add(self.ligand_RSCCBox) - - ligand_rmsdLabel_frame = gtk.Frame() - self.ligand_rmsdLabel = gtk.Label('rmsd') - ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) - self.ligand_rmsdValue = gtk.Label(self.spider_plot_data['PANDDA_site_rmsd']) - ligand_rmsdBox_frame = gtk.Frame() - self.ligand_rmsdBox = gtk.EventBox() - self.ligand_rmsdBox.add(self.ligand_rmsdValue) - ligand_rmsdBox_frame.add(self.ligand_rmsdBox) - - ligand_RSRLabel_frame = gtk.Frame() - self.ligand_RSRLabel = gtk.Label('RSR') - ligand_RSRLabel_frame.add(self.ligand_RSRLabel) - self.ligand_RSRValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSR']) - ligand_RSRBox_frame = gtk.Frame() - self.ligand_RSRBox = gtk.EventBox() - self.ligand_RSRBox.add(self.ligand_RSRValue) - ligand_RSRBox_frame.add(self.ligand_RSRBox) - - ligand_RSZDLabel_frame = gtk.Frame() - self.ligand_RSZDLabel = gtk.Label('RSZD') - ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) - self.ligand_RSZDValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSZD']) - ligand_RSZDBox_frame = gtk.Frame() - self.ligand_RSZDBox = gtk.EventBox() - self.ligand_RSZDBox.add(self.ligand_RSZDValue) - ligand_RSZDBox_frame.add(self.ligand_RSZDBox) - - outer_frame = gtk.Frame() - hbox = gtk.HBox() - - frame = gtk.Frame() - self.table_left = gtk.Table(8, 2, False) - self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) - self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) - self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) - self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) - self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) - self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) - self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) - self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) - self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) - self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) - self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) - self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) - self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) - self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) - self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) - self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) - frame.add(self.table_left) - hbox.add(frame) - - frame = gtk.Frame() - self.table_right = gtk.Table(8, 2, False) - self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) - self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) - self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) - self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) - self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) - self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) - self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) - self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) - self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) - self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) - self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) - self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) - self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) - self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) - self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) - self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) - frame.add(self.table_right) - hbox.add(frame) - - outer_frame.add(hbox) - self.vbox.add(outer_frame) - - hbox = gtk.HBox() - button = gtk.Button(label="Show MolProbity to-do list") - button.connect("clicked", self.show_molprobity_to_do) - hbox.add(button) - # --- ground state mean map --- - self.ground_state_mean_map_button = gtk.Button(label="Show ground state mean map") - self.ground_state_mean_map_button.connect("clicked", self.show_ground_state_mean_map) - hbox.add(self.ground_state_mean_map_button) -# self.vbox.add(self.ground_state_mean_map_button) - self.vbox.add(hbox) - - self.vbox.pack_start(frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- hbox for compound picture & spider_plot (formerly: refinement history) --- - frame = gtk.Frame() - self.hbox_for_info_graphics = gtk.HBox() - - # --- compound picture --- - compound_frame = gtk.Frame() - pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_COMPOUND_IMAGE_AVAILABLE.png')) - self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.image = gtk.Image() - self.image.set_from_pixbuf(self.pic) - compound_frame.add(self.image) - self.hbox_for_info_graphics.add(compound_frame) - - # --- Refinement History --- - # self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) - # self.canvas.set_size_request(190, 190) - # self.hbox_for_info_graphics.add(self.canvas) - - # --- Spider Plot --- - spider_plot_frame = gtk.Frame() - spider_plot_pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image = gtk.Image() - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - spider_plot_frame.add(self.spider_plot_image) - self.hbox_for_info_graphics.add(spider_plot_frame) - - frame.add(self.hbox_for_info_graphics) - self.vbox.add(frame) - - ################################################################################# - # --- pandda.inspect user comments --- -# outer_frame = gtk.Frame(label='pandda.inspect comments') -# vbox = gtk.VBox() -# ligand_site_name_label_frame = gtk.Frame() -# ligand_site_name_label = gtk.Label('Site Name') -# ligand_site_name_label_frame.add(ligand_site_name_label) -# ligand_inspect_confidence_label_frame = gtk.Frame() -# ligand_inspect_confidence_label = gtk.Label('Confidence') -# ligand_inspect_confidence_label_frame.add(ligand_inspect_confidence_label) -# ligand_inspect_interesting_label_frame = gtk.Frame() -# ligand_inspect_interesting_label = gtk.Label('Interesting') -# ligand_inspect_interesting_label_frame.add(ligand_inspect_interesting_label) -# ligand_inspect_comment_label_frame = gtk.Frame() -# ligand_inspect_comment_label = gtk.Label('Comment') -# ligand_inspect_comment_label_frame.add(ligand_inspect_comment_label) -# ligand_site_name_value_frame = gtk.Frame() -# self.ligand_site_name_value = gtk.Label('-') -# ligand_site_name_value_frame.add(self.ligand_site_name_value) -# ligand_inspect_confidence_value_frame = gtk.Frame() -# self.ligand_inspect_confidence_value = gtk.Label('-') -# ligand_inspect_confidence_value_frame.add(self.ligand_inspect_confidence_value) -# ligand_inspect_interesting_value_frame = gtk.Frame() -# self.ligand_inspect_interesting_value = gtk.Label('-') -# ligand_inspect_interesting_value_frame.add(self.ligand_inspect_interesting_value) -# ligand_inspect_comment_value_frame = gtk.Frame() -# self.ligand_inspect_comment_value = gtk.Label('-') -# ligand_inspect_comment_value_frame.add(self.ligand_inspect_comment_value) -# -# frame_pandda_inspect_comments_table = gtk.Frame() -# pandda_inspect_comments_table = gtk.Table(2, 6, False) -# pandda_inspect_comments_table.attach(ligand_site_name_label_frame, 0, 1, 0, 1) -# pandda_inspect_comments_table.attach(ligand_site_name_value_frame, 1, 2, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_confidence_label_frame, 2, 3, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_confidence_value_frame, 3, 4, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_interesting_label_frame, 4, 5, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_interesting_value_frame, 5, 6, 0, 1) -# pandda_inspect_comments_table.attach(ligand_inspect_comment_label_frame, 0, 1, 1, 2) -# pandda_inspect_comments_table.attach(ligand_inspect_comment_value_frame, 1, 6, 1, 2) -# -# frame_pandda_inspect_comments_table.add(pandda_inspect_comments_table) -# vbox.add(frame_pandda_inspect_comments_table) -# outer_frame.add(vbox) -# self.vbox.pack_start(outer_frame) - - # # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - outer_frame = gtk.Frame(label='Sample Navigator') - hboxSample = gtk.HBox() - - # --- crystal navigator combobox --- - frame = gtk.Frame() - self.vbox_sample_navigator = gtk.VBox() - self.cb = gtk.combo_box_new_text() - self.cb.connect("changed", self.ChooseXtal) - self.vbox_sample_navigator.add(self.cb) - # --- crystal navigator backward/forward button --- - self.PREVbutton = gtk.Button(label="<<<") - self.NEXTbutton = gtk.Button(label=">>>") - self.PREVbutton.connect("clicked", self.ChangeXtal, -1) - self.NEXTbutton.connect("clicked", self.ChangeXtal, +1) - hbox = gtk.HBox() - hbox.pack_start(self.PREVbutton) - hbox.pack_start(self.NEXTbutton) - self.vbox_sample_navigator.add(hbox) - frame.add(self.vbox_sample_navigator) - hboxSample.add(frame) - - # --- site navigator combobox --- - frame = gtk.Frame() - self.vbox_site_navigator = gtk.VBox() - self.cb_site = gtk.combo_box_new_text() - self.cb_site.connect("changed", self.ChooseSite) - self.vbox_site_navigator.add(self.cb_site) - # --- site navigator backward/forward button --- - self.PREVbuttonSite = gtk.Button(label="<<<") - self.NEXTbuttonSite = gtk.Button(label=">>>") - self.PREVbuttonSite.connect("clicked", self.ChangeSite, -1) - self.NEXTbuttonSite.connect("clicked", self.ChangeSite, +1) - hbox = gtk.HBox() - hbox.pack_start(self.PREVbuttonSite) - hbox.pack_start(self.NEXTbuttonSite) - self.vbox_site_navigator.add(hbox) - frame.add(self.vbox_site_navigator) - hboxSample.add(frame) - - outer_frame.add(hboxSample) - self.vbox.add(outer_frame) - - # # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# -# outer_frame = gtk.Frame(label='Label') -# hboxlabel = gtk.HBox() -# -# frame = gtk.Frame() -# hbox = gtk.HBox() -# self.vbox_label = gtk.VBox() -# labels = self.db.get_labels_from_db() -# if len(labels) > 5: -# print '==> sorry, too many labels; cannot display them in panel' -# labels = labels[:5] -# # with radiobuttons, one of them needs to be always on -# # but there will be cases when the user has not assigned a label yet -# # hence, the not_shown button is not shown but gets active -# # if the label has not been set yet -# labels.append('not_shown') -# for n, l in enumerate(labels): -# print n,l -# if n == 0: -# new_button = gtk.RadioButton(None, l) -# else: -# new_button = gtk.RadioButton(new_button, l) -# new_button.connect("toggled", self.label_button_clicked, l) -# if not l == 'not_shown': -# hbox.add(new_button) -# self.label_button_list.append(new_button) -# self.vbox_label.add(hbox) -# frame.add(self.vbox_label) -# -# hboxlabel.add(frame) -# -# outer_frame.add(hboxlabel) -# self.vbox.add(outer_frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- current refinement stage --- - outer_frame = gtk.Frame() - hbox = gtk.HBox() - - frame = gtk.Frame(label='Analysis Status') - vbox = gtk.VBox() - self.experiment_stage_button_list = [] - for n, button in enumerate(self.experiment_stage): - if n == 0: - new_button = gtk.RadioButton(None, button[0]) - else: - new_button = gtk.RadioButton(new_button, button[0]) - new_button.connect("toggled", self.experiment_stage_button_clicked, button[1]) - vbox.pack_start(new_button,False,False,0) -# vbox.add(new_button) - self.experiment_stage_button_list.append(new_button) - frame.add(vbox) - hbox.pack_start(frame) - - # --- ligand confidence --- - frame = gtk.Frame(label='Ligand Confidence') - vbox = gtk.VBox() - self.ligand_confidence_button_list = [] - for n, criteria in enumerate(self.ligand_confidence_category): - if n == 0: - new_button = gtk.RadioButton(None, criteria) - else: - new_button = gtk.RadioButton(new_button, criteria) - new_button.connect("toggled", self.ligand_confidence_button_clicked, criteria) - vbox.pack_start(new_button,False,False,0) -# vbox.add(new_button) - self.ligand_confidence_button_list.append(new_button) - frame.add(vbox) - hbox.pack_start(frame) - -# # label section --> start -# frame = gtk.Frame(label='Label') -# vbox = gtk.VBox() -# labels = self.db.get_labels_from_db() -# if len(labels) > 5: -# print '==> sorry, too many labels; cannot display them in panel' -# labels = labels[:5] -# # with radiobuttons, one of them needs to be always on -# # but there will be cases when the user has not assigned a label yet -# # hence, the not_shown button is not shown but gets active -# # if the label has not been set yet -# labels.append('not_shown') -# for n, l in enumerate(labels): -# print n,l -# if n == 0: -# new_button = gtk.RadioButton(None, l) -# else: -# new_button = gtk.RadioButton(new_button, l) -# new_button.connect("toggled", self.label_button_clicked, l) -# if not l == 'not_shown': -# vbox.add(new_button) -# self.label_button_list.append(new_button) -# frame.add(vbox) -# hbox.pack_start(frame) -# # label section <-- end - - outer_frame.add(hbox) - self.vbox.pack_start(outer_frame) - - # SPACER -# self.vbox.add(gtk.Label(' ')) - - # --- ligand modeling --- - frame = gtk.Frame(label='Ligand Modeling') - self.hbox_for_modeling = gtk.HBox() - self.merge_ligand_button = gtk.Button(label="Merge Ligand") - self.place_ligand_here_button = gtk.Button(label="Place Ligand here") - self.hbox_for_modeling.add(self.place_ligand_here_button) - self.place_ligand_here_button.connect("clicked", self.place_ligand_here) - self.hbox_for_modeling.add(self.merge_ligand_button) - self.merge_ligand_button.connect("clicked", self.merge_ligand_into_protein) - self.select_cpd_cb = gtk.combo_box_new_text() - self.select_cpd_cb.connect("changed", self.select_cpd) - self.hbox_for_modeling.add(self.select_cpd_cb) - frame.add(self.hbox_for_modeling) - self.vbox.pack_start(frame) - - # # --- ligand confidence --- - # self.cb_ligand_confidence = gtk.combo_box_new_text() - # self.cb_ligand_confidence.connect("changed", self.set_ligand_confidence) - # for citeria in self.ligand_confidence: - # self.cb_ligand_confidence.append_text(citeria) - # self.vbox.add(self.cb_ligand_confidence) - - - # --- refinement & options --- - self.hbox_for_refinement = gtk.HBox() - self.REFINEbutton = gtk.Button(label="Refine") - self.RefinementParamsButton = gtk.Button(label="refinement parameters") - self.covalentLinksbutton = gtk.Button(label="covalent links\n-define-") - self.covalentLinksCreatebutton = gtk.Button(label="covalent links\n-create & refine-") - self.REFINEbutton.connect("clicked", self.REFINE) - self.hbox_for_refinement.add(self.REFINEbutton) - self.RefinementParamsButton.connect("clicked", self.RefinementParams) - self.covalentLinksbutton.connect("clicked", self.covalentLinkDef) - self.covalentLinksCreatebutton.connect("clicked", self.covalentLinkCreate) - self.hbox_for_refinement.add(self.RefinementParamsButton) - self.hbox_for_refinement.add(self.covalentLinksbutton) - self.hbox_for_refinement.add(self.covalentLinksCreatebutton) - self.vbox.add(self.hbox_for_refinement) - - # self.VALIDATEbutton = gtk.Button(label="validate structure") - # self.DEPOSITbutton = gtk.Button(label="prepare for deposition") - - - # need to put it here, because attributes within refinementProtocolCallback function - # are defined after checkbox is defined - self.refinementProtocolcheckbox.connect("toggled", self.refinementProtocolCallback) - - - # --- CANCEL button --- - self.CANCELbutton = gtk.Button(label="CANCEL") - self.CANCELbutton.connect("clicked", self.CANCEL) - self.vbox.add(self.CANCELbutton) - - self.window.add(self.vbox) - self.window.show_all() - - def CANCEL(self, widget): - self.window.destroy() - - def ChangeXtal(self, widget, data=None): - self.index = self.index + data - if self.index < 0: - self.index = 0 - if self.index >= len(self.Todo): - # self.index = len(self.Todo) - self.index = 0 - self.cb.set_active(self.index) - - def ChooseXtal(self, widget): - self.xtalID = str(widget.get_active_text()) - for n, item in enumerate(self.Todo): - if str(item[0]) == self.xtalID: - self.index = n - self.merge_ligand_button.set_sensitive(True) - self.place_ligand_here_button.set_sensitive(True) - -# self.ligand_site_name_value.set_label('-') -# self.ligand_inspect_confidence_value.set_label('-') -# self.ligand_inspect_interesting_value.set_label('-') -# self.ligand_inspect_comment_value.set_label('-') - - self.refresh_site_combobox() - self.db_dict_mainTable = {} - self.db_dict_panddaTable = {} - if str(self.Todo[self.index][0]) is not None: - self.compoundID = str(self.Todo[self.index][1]) - self.refinement_folder = str(self.Todo[self.index][4]) - self.refinement_outcome = str(self.Todo[self.index][5]) -# self.label = self.db.get_label_of_sample(self.xtalID) -# self.update_label_radiobutton() - self.update_RefinementOutcome_radiobutton() - if self.xtalID not in self.siteDict: # i.e. we are not working with a PanDDA model - self.ligand_confidence = str(self.Todo[self.index][6]) -# self.update_LigandConfidence_radiobutton() -# self.label = self.db.get_label_of_sample(self.xtalID) -# self.update_label_radiobutton() - - self.RefreshData() - - def select_cpd(self, widget): - cpd = str(widget.get_active_text()) - for imol in coot_utils_XChem.molecule_number_list(): - if imol not in self.mol_dict['ligand_stereo']: - continue - molName = coot.molecule_name(imol)[coot.molecule_name(imol).rfind('/')+1:].replace('.pdb','') - if 'rhofit' in coot.molecule_name(imol) or 'phenix' in coot.molecule_name(imol): - molNameCIF = coot.molecule_name(imol)[coot.molecule_name(imol).rfind('/') + 1:].replace('.pdb', '').replace('_phenix','').replace('_rhofit','') - else: - molNameCIF = molName - print cpd,'-',imol,'-',coot.molecule_name(imol) - if molName == cpd: - coot.set_mol_displayed(imol, 1) - print 'reading',os.path.join(self.project_directory,self.xtalID,'compound',molNameCIF+'.cif') - coot.read_cif_dictionary(os.path.join(self.project_directory,self.xtalID,'compound',molNameCIF+'.cif')) - else: - coot.set_mol_displayed(imol, 0) - - - def update_RefinementOutcome_radiobutton(self): - # updating dataset outcome radiobuttons - current_stage = 0 - for i, entry in enumerate(self.experiment_stage): - if entry[1].split()[0] == self.refinement_outcome.split()[0]: - current_stage = i - break - for i, button in enumerate(self.experiment_stage_button_list): - if i == current_stage: - button.set_active(True) - break - -# def update_label_radiobutton(self): -# found = False -# for button in self.label_button_list: -# if button.get_label() == self.label: -# button.set_active(True) -# found = True -# if not found: -# for button in self.label_button_list: -# if button.get_label() == 'not_shown': -# button.set_active(True) -# break - - def update_LigandConfidence_radiobutton(self): - # updating ligand confidence radiobuttons - current_stage = 0 - for i, entry in enumerate(self.ligand_confidence_category): - print '--->', entry, self.ligand_confidence - try: - if entry.split()[0] == self.ligand_confidence.split()[0]: - current_stage = i - break - except IndexError: - pass - for i, button in enumerate(self.ligand_confidence_button_list): - if i == current_stage: - button.set_active(True) - break - - def refresh_site_combobox(self): - # reset self.pandda_index - self.pandda_index = -1 - # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever be 100 sites - for n in range(-1, 100): - self.cb_site.remove_text(0) - self.site_index = '0' - self.event_index = '0' - # only repopulate if site exists - if self.xtalID in self.siteDict: - for item in sorted(self.siteDict[self.xtalID]): - self.cb_site.append_text('site: {0!s} - event: {1!s}'.format(item[5], item[6])) - - def ChangeSite(self, widget, data=None): - if self.xtalID in self.siteDict: - self.pandda_index = self.pandda_index + data - if self.pandda_index < 0: - self.pandda_index = 0 - if self.pandda_index >= len(self.siteDict[self.xtalID]): - self.pandda_index = 0 - self.cb_site.set_active(self.pandda_index) - - def ChooseSite(self, widget): - tmp = str(widget.get_active_text()) - print self.siteDict - print self.site_index - self.site_index = tmp.split()[1] - self.event_index = tmp.split()[4] - for n, item in enumerate(self.siteDict[self.xtalID]): - if item[5] == self.site_index and item[6] == self.event_index: - self.pandda_index = n - self.RefreshSiteData() - - def RefreshSiteData(self): - - if self.pandda_index == -1: - self.merge_ligand_button.set_sensitive(True) - self.place_ligand_here_button.set_sensitive(True) - else: - self.merge_ligand_button.set_sensitive(False) - self.place_ligand_here_button.set_sensitive(False) - # and remove ligand molecule so that there is no temptation to merge it - if len(coot_utils_XChem.molecule_number_list()) > 0: - for imol in coot_utils_XChem.molecule_number_list(): - if self.compoundID + '.pdb' in coot.molecule_name(imol): - coot.close_molecule(imol) - -# for w in self.label_button_list: -# w.set_active(False) - - - print 'pandda index', self.pandda_index - self.spider_plot = self.siteDict[self.xtalID][self.pandda_index][4] - print 'new spider plot:', self.spider_plot - self.event_map = self.siteDict[self.xtalID][self.pandda_index][0] - print 'new event map:', self.event_map - self.ligand_confidence = str(self.siteDict[self.xtalID][self.pandda_index][7]) - self.update_LigandConfidence_radiobutton() - site_x = float(self.siteDict[self.xtalID][self.pandda_index][1]) - site_y = float(self.siteDict[self.xtalID][self.pandda_index][2]) - site_z = float(self.siteDict[self.xtalID][self.pandda_index][3]) - print 'new site coordinates:', site_x, site_y, site_z - coot.set_rotation_centre(site_x, site_y, site_z) - -# self.ligand_site_name_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][8])) -# self.ligand_inspect_confidence_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][9])) -# self.ligand_inspect_interesting_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][10])) -# self.ligand_inspect_comment_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][11])) - - self.spider_plot_data = self.db.get_db_pandda_dict_for_sample_and_site_and_event(self.xtalID, self.site_index, - self.event_index) - print '>>>>> spider plot data', self.spider_plot_data - self.ligandIDValue.set_label(self.spider_plot_data['PANDDA_site_ligand_id']) - try: - self.ligand_occupancyValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_occupancy']), 2))) - except ValueError: - self.ligand_occupancyValue.set_label('-') - - try: - self.ligand_BaverageValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_B_average']), 2))) - except ValueError: - self.ligand_BaverageValue.set_label('-') - - try: - self.ligand_BratioSurroundingsValue.set_label( - str(round(float(self.spider_plot_data['PANDDA_site_B_ratio_residue_surroundings']), 2))) - except ValueError: - self.ligand_BratioSurroundingsValue.set_label('-') - - try: - self.ligand_RSCCValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_RSCC']), 2))) - except ValueError: - self.ligand_RSCCValue.set_label('-') - - try: - self.ligand_rmsdValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_rmsd']), 2))) - except ValueError: - self.ligand_rmsdValue.set_label('-') - - try: - self.ligand_RSRValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_RSR']), 2))) - except ValueError: - self.ligand_RSRValue.set_label('-') - - try: - self.ligand_RSZDValue.set_label(str(round(float(self.spider_plot_data['PANDDA_site_RSZD']), 2))) - except ValueError: - self.ligand_RSZDValue.set_label('-') - - ######################################################################################### - # delete old Event MAPs - if len(coot_utils_XChem.molecule_number_list()) > 0: - for imol in coot_utils_XChem.molecule_number_list(): - if 'map.native.ccp4' in coot.molecule_name(imol): - coot.close_molecule(imol) - - ######################################################################################### - # Spider plot - # Note: refinement history was shown instead previously - if os.path.isfile(self.spider_plot): - spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) - else: - spider_plot_pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = spider_plot_pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - - ######################################################################################### - # check for PANDDAs EVENT maps - if os.path.isfile(self.event_map): - coot.set_colour_map_rotation_on_read_pdb(0) - coot.handle_read_ccp4_map((self.event_map), 0) - for imol in coot_utils_XChem.molecule_number_list(): - if self.event_map in coot.molecule_name(imol): - coot.set_contour_level_in_sigma(imol, 2) - # coot.set_contour_level_absolute(imol,0.5) - # coot.set_last_map_colour(0.4,0,0.4) - coot.set_last_map_colour(0.74, 0.44, 0.02) - - def experiment_stage_button_clicked(self, widget, data=None): - self.db_dict_mainTable['RefinementOutcome'] = data - self.Logfile.insert('==> COOT: setting Refinement Outcome for ' + self.xtalID + ' to ' + str( - data) + ' in mainTable of datasource') -# print '==> XCE: setting Refinement Outcome for ' + self.xtalID + ' to ' + str( -# data) + ' in mainTable of datasource' -# self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - self.db.create_or_remove_missing_records_in_depositTable(self.xce_logfile,self.xtalID,'ligand_bound',self.db_dict_mainTable) - - def ligand_confidence_button_clicked(self, widget, data=None): - print 'PANDDA_index', self.pandda_index - if self.pandda_index == -1: - self.db_dict_mainTable['RefinementLigandConfidence'] = data - self.Logfile.insert('==> COOT: setting Ligand Confidence for ' + self.xtalID + ' to ' + str( - data) + ' in mainTable of datasource') -# print '==> XCE: setting Ligand Confidence for ' + self.xtalID + ' to ' + str( -# data) + ' in mainTable of datasource' - self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - self.Todo[self.index][6] = data - else: - self.db_dict_panddaTable['PANDDA_site_confidence'] = data - self.Logfile.insert('==> COOT: setting Ligand Confidence for ' + self.xtalID + ' (site=' + str( - self.site_index) + ', event=' + str(self.event_index) + ') to ' + str( - data) + ' in panddaTable of datasource') -# print '==> XCE: setting Ligand Confidence for ' + self.xtalID + ' (site=' + str( -# self.site_index) + ', event=' + str(self.event_index) + ') to ' + str( -# data) + ' in panddaTable of datasource' - self.db.update_site_event_panddaTable(self.xtalID, self.site_index, self.event_index, - self.db_dict_panddaTable) - self.siteDict[self.xtalID][self.pandda_index][7] = data - -# def update_label(self, widget): -# print '\n\n\n>>>>>>>>>>>>>>>>>>>>>>>>' -# # widget.pressed() -# for w in self.label_button_list: -# print w.get_label(), w.get_active() -# if w != widget: -# w.set_active(False) -# print '<<<<<<<<<<<<<<<<<<<<<<<<<<' -# self.db_dict_mainTable['label'] = widget.get_label() -# print '==> XCE: setting label for ' + self.xtalID + ' to ' + str( -# widget.get_label()) + ' in mainTable of datasource' -# self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - -# def label_button_clicked(self, widget, data=None): -# print '............',data -# if data == 'not_shown': -# self.db.execute_statement("update mainTable set label=Null where CrystalName = '%s'" %self.xtalID) -# else: -# self.db_dict_mainTable['label'] = data -# print '==> XCE: setting label for ' + self.xtalID + ' to ' + str(data) + ' in mainTable of datasource' -# self.db.update_data_source(self.xtalID, self.db_dict_mainTable) - - def RefreshData(self): - # reset spider plot image - spider_plot_pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = spider_plot_pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - - # reset ground state mean map - self.ground_state_mean_map = '' - self.ground_state_mean_map_button.set_sensitive(False) - self.ground_state_mean_map_button.set_label('Show ground state mean map') - if os.path.isfile( - os.path.join(self.project_directory, self.xtalID, self.xtalID + '-ground-state-mean-map.native.ccp4')): - self.ground_state_mean_map_button.set_sensitive(True) - self.ground_state_mean_map = os.path.join(self.project_directory, self.xtalID, - self.xtalID + '-ground-state-mean-map.native.ccp4') - - # initialize Refinement library - self.Refine = XChemRefine.Refine(self.project_directory, self.xtalID, self.compoundID, self.data_source) - self.Serial = XChemRefine.GetSerial(self.project_directory, self.xtalID) - self.panddaSerial = panddaSerial = m = (4 - len(str(self.Serial))) * '0' + str(self.Serial) - # self.Serial=self.Refine.GetSerial() - if self.Serial == 1: - # i.e. no refinement has been done; data is probably straight out of dimple - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.pdb_style)): - print '==> XCE: updating quality indicators in data source for ' + self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID, self.data_source, - os.path.join(self.project_directory, self.xtalID, - self.pdb_style)) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID, self.data_source, - '') # '' because file does not exist - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'init.pdb')): - print '==> XCE: updating quality indicators in data source for ' + self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID, self.data_source, - os.path.join(self.project_directory, self.xtalID, - 'init.pdb')) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID, self.data_source, - '') # '' because file does not exist - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'dimple.pdb')): - print '==> XCE: updating quality indicators in data source for ' + self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID, self.data_source, - os.path.join(self.project_directory, self.xtalID, - 'dimple.pdb')) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID, self.data_source, - '') # '' because file does not exist - - # all this information is now updated in the datasource after each refinement cycle - self.QualityIndicators = self.db.get_db_dict_for_sample(self.xtalID) - - ######################################################################################### - # history - # if the structure was previously refined, try to read the parameters - # self.hbox_for_info_graphics.remove(self.canvas) - if self.Serial > 1: - self.RefmacParams = self.Refine.ParamsFromPreviousCycle(self.Serial - 1) - print '==> REFMAC params:', self.RefmacParams - # refinement_cycle,Rfree,Rcryst=self.Refine.GetRefinementHistory() - # self.canvas = FigureCanvas(self.update_plot(refinement_cycle,Rfree,Rcryst)) - # else: - # self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) # a gtk.DrawingArea - # self.canvas.set_size_request(190, 190) - # self.hbox_for_info_graphics.add(self.canvas) - # self.canvas.show() - - ######################################################################################### - # ligand files - # first remove old samples if present - print '>>>',self.mol_dict['ligand_stereo'] - for n, item in enumerate(self.mol_dict['ligand_stereo']): - print '__',item - self.select_cpd_cb.remove_text(0) - print 'done' - - ######################################################################################### - # remove potential generic line which indicates a possible covalent link - generic_object_clear(self.covLinkObject) - self.covLinkAtomSpec = None - - ######################################################################################### - # reset covalent links - self.covLinks = ['X', 'X', 'X', 'X'] - - ######################################################################################### - # update pdb & maps - - ######################################################################################### - # delete old PDB and MAP files - # - get a list of all molecules which are currently opened in COOT - # - remove all molecules/ maps before loading a new set - if len(coot_utils_XChem.molecule_number_list()) > 0: - for item in coot_utils_XChem.molecule_number_list(): - coot.close_molecule(item) - - ######################################################################################### - # read new PDB files - # read protein molecule after ligand so that this one is the active molecule - coot.set_nomenclature_errors_on_read("ignore") - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.compoundID + '.pdb')): - coot.set_colour_map_rotation_on_read_pdb(0) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, self.compoundID + '.pdb'), 0) - self.mol_dict['ligand'] = imol - coot.read_cif_dictionary(os.path.join(self.project_directory, self.xtalID, self.compoundID + '.cif')) - self.select_cpd_cb.append_text(self.compoundID) - self.mol_dict['ligand_stereo'] = [] - self.mol_dict['ligand_stereo'].append(imol) - # ligands in compound directory - for cifFile in sorted(glob.glob(os.path.join(self.project_directory,self.xtalID,'compound',self.compoundID+'_*.pdb'))): - cif = cifFile[cifFile.rfind('/')+1:] - if '_with_H' in cif: - continue - self.select_cpd_cb.append_text(cif.replace('.pdb','')) - imol = coot.handle_read_draw_molecule_with_recentre(cifFile, 0) - self.mol_dict['ligand_stereo'].append(imol) - coot.set_mol_displayed(imol,0) - # autofitted ligands - for pdbFile in sorted(glob.glob(os.path.join(self.project_directory,self.xtalID,'autofit_ligand','*','*.pdb'))): - autofitRun = pdbFile.split('/')[len(pdbFile.split('/')) - 2] - if pdbFile.endswith(autofitRun+'.pdb'): - self.select_cpd_cb.append_text(autofitRun) - imol = coot.handle_read_draw_molecule_with_recentre(pdbFile, 0) - self.mol_dict['ligand_stereo'].append(imol) - coot.set_mol_displayed(imol, 0) - self.select_cpd_cb.set_sensitive(True) - self.select_cpd_cb.set_active(0) - else: - print 'no compound found in sample directory' -# self.select_cpd_cb.append_text('') - self.select_cpd_cb.set_sensitive(False) - - if not os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.pdb_style)): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - - if self.refinementProtocol.startswith('pandda'): - self.Logfile.insert('==> COOT: looking for ground-state model ' + os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.ground-state.pdb')) -# print '=> XCE: looking for ground-state model', os.path.join(self.project_directory, self.xtalID, -# self.pdb_style.replace('.pdb', -# '') + '.split.ground-state.pdb') - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', '') + '.split.ground-state.pdb')): - self.Logfile.insert('==> COOT: found ground-state model') -# print '=> XCE: found ground-state model' - os.chdir(os.path.join(self.project_directory, self.xtalID)) - coot.set_colour_map_rotation_on_read_pdb(0) - try: - color_wheel_rotation = 160 / float(imol + 2) - except UnboundLocalError: - color_wheel_rotation = 80 - coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) - imol = coot.handle_read_draw_molecule_with_recentre(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.ground-state.pdb'), - 0) - coot.set_colour_by_molecule(imol) - coot.set_mol_active(imol, 0) - else: - self.Logfile.error('==> COOT - cannot find ground-state model') -# print '=> XCE - ERROR: cannot find ground-state model' - self.Logfile.insert('==> COOT: looking for bound-state model '+ os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.bound-state.pdb')) -# print '=> XCE: looking for bound-state model', os.path.join(self.project_directory, self.xtalID, -# self.pdb_style.replace('.pdb', -# '') + '.split.bound-state.pdb') - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', '') + '.split.bound-state.pdb')): - self.Logfile.insert('==> COOT: found bound-state model') -# print '=> XCE: found bound-state model' - os.chdir(os.path.join(self.project_directory, self.xtalID)) - coot.set_colour_map_rotation_on_read_pdb(0) - color_wheel_rotation = 21 / float(imol + 2) - coot.set_colour_map_rotation_on_read_pdb(color_wheel_rotation) - imol = coot.handle_read_draw_molecule_with_recentre(os.path.join(self.project_directory, self.xtalID, - self.pdb_style.replace('.pdb', - '') + '.split.bound-state.pdb'), - 0) - self.mol_dict['protein'] = imol - else: - self.Logfile.error('==> COOT: cannot find bound-state model') -# print '=> XCE - ERROR: cannot find bound-state model' - self.Logfile.warning('==> COOT: moving to next crystal...') -# print '=> XCE: moving to next crystal...' - self.go_to_next_xtal() - else: - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.pdb_style)): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, self.pdb_style), 0) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'init.pdb')): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, 'init.pdb'), 0) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'dimple.pdb')): - os.chdir(os.path.join(self.project_directory, self.xtalID)) - imol = coot.handle_read_draw_molecule_with_recentre( - os.path.join(self.project_directory, self.xtalID, 'dimple.pdb'), 0) - else: - self.go_to_next_xtal() - self.mol_dict['protein'] = imol - - # read any one event map if present - for event_map in glob.glob( - os.path.join(self.project_directory, self.xtalID, self.xtalID + '-event_*.native.ccp4')): - coot.handle_read_ccp4_map((event_map), 0) - coot.set_contour_level_in_sigma(imol, 2) - coot.set_last_map_colour(0.74, 0.44, 0.02) - break - - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith( - self.pdb_style.replace('.pdb', '') + '.split.bound-state.pdb') or coot.molecule_name( - item).endswith(self.pdb_style): - coot.set_show_symmetry_master(1) # master switch to show symmetry molecules - coot.set_show_symmetry_molecule(item, 1) # show symm for model - - ######################################################################################### - # read fofc maps - # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map - # read 2fofc map last so that one can change its contour level - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, '2fofc.map')): - coot.set_colour_map_rotation_on_read_pdb(0) - coot.set_default_initial_contour_level_for_difference_map(3) - coot.handle_read_ccp4_map(os.path.join(self.project_directory, self.xtalID, 'fofc.map'), 1) - coot.set_default_initial_contour_level_for_map(1) - coot.handle_read_ccp4_map(os.path.join(self.project_directory, self.xtalID, '2fofc.map'), 0) - coot.set_last_map_colour(0, 0, 1) - else: - # try to open mtz file with same name as pdb file - coot.set_default_initial_contour_level_for_map(1) - # if not os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.mtz_style)): - # os.chdir(os.path.join(self.project_directory,self.xtalID)) - # if not os.path.isfile('REFINEMENT_IN_PROGRESS'): - # if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.xtalID+'-pandda-input.mtz')): - # os.symlink(self.xtalID+'-pandda-input.mtz',self.mtz_style) - # elif os.path.isfile(os.path.join(self.project_directory,self.xtalID,'dimple.mtz')): - # os.symlink('dimple.mtz',self.mtz_style) - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.mtz_style)): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory, self.xtalID, self.mtz_style)) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'init.mtz')): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory, self.xtalID, 'init.mtz')) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'dimple.mtz')): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory, self.xtalID, 'dimple.mtz')) - - ######################################################################################### - # update Quality Indicator table - try: - self.RRfreeValue.set_label(str(round(float(self.QualityIndicators['RefinementRcryst']), 3)) + ' / ' + str( - round(float(self.QualityIndicators['RefinementRfree']), 3))) - except ValueError: - self.RRfreeValue.set_label('-') - - try: - self.RRfreeBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementRfreeTraficLight'])) - except ValueError: - pass - self.ResolutionValue.set_label(self.QualityIndicators['RefinementResolution']) - try: - self.ResolutionBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementResolutionTL'])) - except ValueError: - pass - self.MolprobityScoreValue.set_label(self.QualityIndicators['RefinementMolProbityScore']) - try: - self.MolprobityScoreBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse( - self.QualityIndicators['RefinementMolProbityScoreTL'])) - except ValueError: - pass - self.RamachandranOutliersValue.set_label(self.QualityIndicators['RefinementRamachandranOutliers']) - try: - self.RamachandranOutliersBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse( - self.QualityIndicators['RefinementRamachandranOutliersTL'])) - except ValueError: - pass - self.RamachandranFavoredValue.set_label(self.QualityIndicators['RefinementRamachandranFavored']) - try: - self.RamachandranFavoredBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse( - self.QualityIndicators['RefinementRamachandranFavoredTL'])) - except ValueError: - pass - self.rmsdBondsValue.set_label(self.QualityIndicators['RefinementRmsdBonds']) - try: - self.rmsdBondsBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementRmsdBondsTL'])) - except ValueError: - pass - self.rmsdAnglesValue.set_label(self.QualityIndicators['RefinementRmsdAngles']) - try: - self.rmsdAnglesBox.modify_bg(gtk.STATE_NORMAL, - gtk.gdk.color_parse(self.QualityIndicators['RefinementRmsdAnglesTL'])) - except ValueError: - pass - self.MatrixWeightValue.set_label(self.QualityIndicators['RefinementMatrixWeight']) - - try: - pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(self.project_directory, self.xtalID, self.compoundID + '.png')) - except gobject.GError: - pic = gtk.gdk.pixbuf_new_from_file( - os.path.join(os.getenv('XChemExplorer_DIR'), 'image', 'NO_COMPOUND_IMAGE_AVAILABLE.png')) - self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.image.set_from_pixbuf(self.pic) - - def go_to_next_xtal(self): - self.index += 1 - if self.index >= len(self.Todo): - self.index = len(self.Todo) - self.cb.set_active(self.index) - - def REFINE(self, widget): - self.start_refinement() - - def start_refinement(self): - # ####################################################### - # if not os.path.isdir(os.path.join(self.project_directory,self.xtalID,'cootOut')): - # os.mkdir(os.path.join(self.project_directory,self.xtalID,'cootOut')) - # # create folder for new refinement cycle - # os.mkdir(os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial))) - # - # ####################################################### - # # write PDB file - # # now take protein pdb file and write it to newly create Refine_ folder - # # note: the user has to make sure that the ligand file was merged into main file - # for item in coot_utils_XChem.molecule_number_list(): - # if coot.molecule_name(item).endswith(self.pdb_style.replace('.pdb','')+'.split.bound-state.pdb') or coot.molecule_name(item).endswith(self.pdb_style): - # coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial),'refine.modified.pdb')) - # break - # elif coot.molecule_name(item).endswith('dimple.pdb'): - # coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial),'refine.modified.pdb')) - # break - # - - ####################################################### - if self.refinementProtocol.startswith('pandda'): - - ####################################################### - if not os.path.isdir(os.path.join(self.project_directory, self.xtalID, 'cootOut')): - os.mkdir(os.path.join(self.project_directory, self.xtalID, 'cootOut')) - # create folder for new refinement cycle - try: - self.Logfile.insert('==> COOT: trying to make folder: %s' %os.path.join(self.project_directory, self.xtalID, 'cootOut', 'Refine_' + str(self.Serial))) - os.mkdir(os.path.join(self.project_directory, self.xtalID, 'cootOut', 'Refine_' + str(self.Serial))) - except OSError: - self.Logfile.warning('==> COOT: folder exists; will overwrite contents!') -# print '==> XCE: WARNING -> folder exists; will overwrite contents!' - self.Logfile.warning('==> COOT: it is advised to check the sample directory as this might be a symptom for a PDB file problem') - - ####################################################### - # write PDB file - # now take protein pdb file and write it to newly create Refine_ folder - # note: the user has to make sure that the ligand file was merged into main file - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith( - self.pdb_style.replace('.pdb', '') + '.split.bound-state.pdb') or coot.molecule_name( - item).endswith(self.pdb_style): - coot.write_pdb_file(item, os.path.join(self.project_directory, self.xtalID, 'cootOut', - 'Refine_' + str(self.Serial), 'refine.modified.pdb')) - break - # elif coot.molecule_name(item).endswith('dimple.pdb'): - # coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'cootOut','Refine_'+str(self.Serial),'refine.modified.pdb')) - # break - - XChemRefine.panddaRefine(self.project_directory, self.xtalID, self.compoundID, - self.data_source).RunQuickRefine(self.Serial, self.RefmacParams, - self.external_software, self.xce_logfile, - self.refinementProtocol) - else: - ####################################################### - # create folder for new refinement cycle and check if free.mtz exists - if not os.path.isdir(os.path.join(self.project_directory, self.xtalID)): - os.mkdir(os.path.join(self.project_directory, self.xtalID)) - if not os.path.isdir(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial))): - os.mkdir(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial))) - - ####################################################### - # write PDB file - # now take protein pdb file and write it to newly create Refine_ folder - # note: the user has to make sure that the ligand file was merged into main file - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith(self.pdb_style): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial), - 'in.pdb')) - break - elif coot.molecule_name(item).endswith('refine.split.bound-state.pdb'): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, - 'Refine_' + str(self.Serial), - 'in.pdb')) - break - elif coot.molecule_name(item).endswith('init.pdb'): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial), - 'in.pdb')) - break - elif coot.molecule_name(item).endswith('dimple.pdb'): - coot.write_pdb_file(item, - os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial), - 'in.pdb')) - break - - self.Refine.RunRefmac(self.Serial, self.RefmacParams, self.external_software, self.xce_logfile, self.covLinkAtomSpec) - - self.index += 1 - if self.index >= len(self.Todo): - # self.index = len(self.Todo) - self.index = 0 - self.cb.set_active(self.index) - - def RefinementParams(self, widget): - print '\n==> XCE: changing refinement parameters' - self.RefmacParams = XChemRefine.RefineParams(self.project_directory, self.xtalID, self.compoundID, - self.data_source).RefmacRefinementParams(self.RefmacParams) - - def covalentLinkDef(self, widget): - coot.user_defined_click_py(2,self.show_potential_link) - - def show_potential_link(self,*clicks): - # first find imol of protein molecule - # it's a prerequisite that the ligand is merged into the protein - imol_protein = None - for imol in coot_utils_XChem.molecule_number_list(): - print '>',coot.molecule_name(imol) - if coot.molecule_name(imol).endswith(self.pdb_style) or coot.molecule_name(imol).endswith('init.pdb') or coot.molecule_name(imol).endswith('dimple.pdb'): - imol_protein = imol - break - - print 'please click on the two atoms you want to link' - if (len(clicks) == 2): - click_1 = clicks[0] - click_2 = clicks[1] - imol_1 = click_1[1] - imol_2 = click_2[1] - print 'imolp',imol,'imo11',imol_1,'imol2',imol_2 - if imol_1 == imol_2 and imol_1 == imol_protein: - print 'click_1',click_1 - self.covLinkAtomSpec = None - xyz_1 = atom_info_string(click_1[1],click_1[2],click_1[3],click_1[4],click_1[5],click_1[6]) - residue_1 = residue_name(click_1[1],click_1[2],click_1[3],click_1[4]) - xyz_2 = atom_info_string(click_2[1],click_2[2],click_2[3],click_2[4],click_2[5],click_2[6]) - residue_2 = residue_name(click_2[1],click_2[2],click_2[3],click_2[4]) - thick = 4 - to_generic_object_add_line(self.covLinkObject, "yellowtint", thick, xyz_1[3], xyz_1[4], xyz_1[5], xyz_2[3], xyz_2[4], xyz_2[5]) - set_display_generic_object(self.covLinkObject, 1) - self.covLinkAtomSpec = [imol_protein,click_1,click_2,residue_1,residue_2] - else: - print 'error: both atoms must belong to the same object; did you merge the ligand with your protein?' - - def covalentLinkCreate(self, widget): - if self.covLinkAtomSpec is not None: - imol = self.covLinkAtomSpec[0] - atom1 = self.covLinkAtomSpec[1][1:] - atom2 = self.covLinkAtomSpec[2][1:] - residue_1 = self.covLinkAtomSpec[3] - residue_2 = self.covLinkAtomSpec[4] - make_link(imol, atom1, atom2, residue_1+'-'+residue_2, 1.7) - generic_object_clear(self.covLinkObject) - self.start_refinement() - else: - print 'error: no covalent link defined' - - def set_selection_mode(self, widget): - self.selection_mode = widget.get_active_text() - - def get_samples_to_look_at(self, widget): - if self.selection_mode == '': - self.status_label.set_text('select model stage') - return - self.status_label.set_text('checking datasource for samples... ') - # first remove old samples if present - if len(self.Todo) != 0: - for n, item in enumerate(self.Todo): - self.cb.remove_text(0) - self.Todo = [] - self.siteDict = {} - self.Todo, self.siteDict = self.db.get_todoList_for_coot(self.selection_mode) - self.status_label.set_text('found {0!s} samples'.format(len(self.Todo))) - # refresh sample CB - for item in sorted(self.Todo): - self.cb.append_text('{0!s}'.format(item[0])) - if self.siteDict == {}: - self.cb_site.set_sensitive(False) - self.PREVbuttonSite.set_sensitive(False) - self.NEXTbuttonSite.set_sensitive(False) - else: - self.cb_site.set_sensitive(True) - self.PREVbuttonSite.set_sensitive(True) - self.NEXTbuttonSite.set_sensitive(True) - - def update_plot(self, refinement_cycle, Rfree, Rcryst): - fig = Figure(figsize=(2, 2), dpi=50) - Plot = fig.add_subplot(111) - Plot.set_ylim([0, max(Rcryst + Rfree)]) - Plot.set_xlabel('Refinement Cycle', fontsize=12) - Plot.plot(refinement_cycle, Rfree, label='Rfree', linewidth=2) - Plot.plot(refinement_cycle, Rcryst, label='Rcryst', linewidth=2) - Plot.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, - ncol=2, mode="expand", borderaxespad=0., fontsize=12) - return fig - - def place_ligand_here(self, widget): - cpd = str(self.select_cpd_cb.get_active_text()) - for imol in coot_utils_XChem.molecule_number_list(): - if imol not in self.mol_dict['ligand_stereo']: - continue - molName = coot.molecule_name(imol)[coot.molecule_name(imol).rfind('/')+1:].replace('.pdb','') - if molName == cpd: - print '===> XCE: moving ligand to pointer' - coot_utils_XChem.move_molecule_here(imol) - print 'LIGAND: ', molName -# print '===> XCE: moving ligand to pointer' -# # coot.move_molecule_here() -# print 'LIGAND: ', self.mol_dict['ligand'] -# coot_utils_XChem.move_molecule_here(self.mol_dict['ligand']) - - - def merge_ligand_into_protein(self, widget): - cpd = str(self.select_cpd_cb.get_active_text()) - for imol in coot_utils_XChem.molecule_number_list(): - if imol not in self.mol_dict['ligand_stereo']: - continue - molName = coot.molecule_name(imol)[coot.molecule_name(imol).rfind('/')+1:].replace('.pdb','') - if molName == cpd: - print '===> XCE: merge ligand into protein structure -->',cpd - coot.merge_molecules_py([imol], self.mol_dict['protein']) - if 'rhofit' in coot.molecule_name(imol) or 'phenix' in coot.molecule_name(imol): - molName = coot.molecule_name(imol)[coot.molecule_name(imol).rfind('/') + 1:].replace('.pdb', '').replace('_phenix','').replace('_rhofit','') - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.compoundID + '.cif')): - os.system('/bin/rm %s' % os.path.join(self.project_directory, self.xtalID, self.compoundID + '.cif')) - print 'XCE: changing directory', os.path.join(self.project_directory, self.xtalID) - os.chdir(os.path.join(self.project_directory, self.xtalID)) - print 'XCE: changing symlink ln -s %s %s.cif' % ( - os.path.join('compound', molName + '.cif'), self.compoundID) - os.system('ln -s %s %s.cif' % (os.path.join('compound', molName + '.cif'), self.compoundID)) - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, self.compoundID + '.pdb')): - os.system('/bin/rm %s' % os.path.join(self.project_directory, self.xtalID, self.compoundID + '.pdb')) - print 'XCE: changing directory', os.path.join(self.project_directory, self.xtalID) - os.chdir(os.path.join(self.project_directory, self.xtalID)) - print 'XCE: changing symlink ln -s %s %s.pdb' % ( - os.path.join('compound', molName + '.pdb'), self.compoundID) - os.system('ln -s %s %s.pdb' % (os.path.join('compound', molName - + '.pdb'), self.compoundID)) - print '===> XCE: deleting ligand molecule',molName - coot.close_molecule(imol) - - self.select_cpd_cb.set_sensitive(False) - -# print '===> XCE: merge ligand into protein structure' -# # merge_molecules(list(imols), imol) e.g. merge_molecules([1],0) -# coot.merge_molecules_py([self.mol_dict['ligand']], self.mol_dict['protein']) -# print '===> XCE: deleting ligand molecule' -# coot.close_molecule(self.mol_dict['ligand']) - - def show_molprobity_to_do(self, widget): - print self.panddaSerial - AdjPanddaSerial = (4 - len(str(self.Serial))) * '0' + str(int(self.panddaSerial) - 1) - print os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.panddaSerial), - 'molprobity_coot.py') - if os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial - 1), - 'molprobity_coot.py')): - print '==> XCE: running MolProbity Summary for', self.xtalID - coot.run_script(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(self.Serial - 1), - 'molprobity_coot.py')) - elif os.path.isfile(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(AdjPanddaSerial), - 'molprobity_coot.py')): - print '==> XCE: running MolProbity Summary for', self.xtalID - coot.run_script(os.path.join(self.project_directory, self.xtalID, 'Refine_' + str(AdjPanddaSerial), - 'molprobity_coot.py')) - else: - print '==> XCE: cannot find ' + os.path.join(self.project_directory, self.xtalID, - 'Refine_' + str(self.Serial - 1), 'molprobity_coot.py') - - def refinementProtocolCallback(self, widget): - if widget.get_active(): - if self.refinementProtocolcheckbox.get_active(): - self.refinementProtocol = 'pandda_phenix' - else: - self.refinementProtocol = 'pandda_refmac' - self.PREVbuttonSite.set_sensitive(True) - self.NEXTbuttonSite.set_sensitive(True) - else: - self.refinementProtocolcheckbox.set_active(False) - self.refinementProtocol = 'refmac' - self.PREVbuttonSite.set_sensitive(False) - self.NEXTbuttonSite.set_sensitive(False) - print self.refinementProtocol - - def refinementProgramCallback(self, widget): - if widget.get_active(): - if self.refinementProtocolcheckbox.get_active(): - self.refinementProtocol = 'pandda_phenix' - self.RefinementParamsButton.set_sensitive(False) - else: - self.refinementProgramcheckbox.set_active(False) - self.refinementProtocol = 'refmac' - else: - self.RefinementParamsButton.set_sensitive(True) - if self.refinementProtocolcheckbox.get_active(): - self.refinementProtocol = 'pandda_refmac' - else: - self.refinementProtocol = 'refmac' - print self.refinementProtocol - - def show_ground_state_mean_map(self, widget): - if widget.get_label().startswith('Show'): - loaded = False - for imol in coot_utils_XChem.molecule_number_list(): - if 'ground-state-mean-map' in coot.molecule_name(imol): - coot.set_map_displayed(imol, 1) - loaded = True - break - if not loaded: - coot.set_default_initial_contour_level_for_map(1) - coot.handle_read_ccp4_map(self.ground_state_mean_map, 0) - coot.set_last_map_colour(0.6, 0.6, 0) - widget.set_label('Undisplay ground state mean map') - else: - for imol in coot_utils_XChem.molecule_number_list(): - if 'ground-state-mean-map' in coot.molecule_name(imol): - coot.set_map_displayed(imol, 0) - widget.set_label('Show ground state mean map') - - -if __name__ == '__main__': - GUI().StartGUI() diff --git a/lib/XChemCootOld.py b/lib/XChemCootOld.py deleted file mode 100755 index 73654740..00000000 --- a/lib/XChemCootOld.py +++ /dev/null @@ -1,1107 +0,0 @@ -# last edited: 21/07/2017 - 15:00 - -import gobject -import sys -import os -import pickle - -from matplotlib.figure import Figure -#from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas - -# XCE libraries -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -import XChemDB -import XChemRefine -import XChemUtils - -# libraries from COOT -import pygtk, gtk, pango -import coot - -# had to adapt the original coot_utils.py file -# otherwise unable to import the original file without complaints about missing modules etc. -# modified file is now in $XChemExplorer_DIR/lib -import coot_utils_XChem - - -class GUI(object): - - """ - main class which opens the actual GUI - """ - - def __init__(self): - - ########################################################################################### - # read in settings file from XChemExplorer to set the relevant paths - print 'current dir',os.getcwd() - self.settings = pickle.load(open(".xce_settings.pkl","rb")) - remote_qsub_submission=self.settings['remote_qsub'] - print 'setting',self.settings -# self.refine_model_directory=self.settings['refine_model_directory'] - self.database_directory=self.settings['database_directory'] - self.xce_logfile=self.settings['xce_logfile'] - self.data_source=self.settings['data_source'] - self.db=XChemDB.data_source(self.data_source) - - # checking for external software packages - self.external_software=XChemUtils.external_software(self.xce_logfile).check() - self.external_software['qsub_remote']=remote_qsub_submission - - self.selection_criteria = [ '0 - All Datasets', - '1 - Analysis Pending', - '2 - PANDDA model', - '3 - In Refinement', - '4 - CompChem ready', - '5 - Deposition ready', - '6 - Deposited' ] - - self.experiment_stage = [ ['Review PANDDA export', '2 - PANDDA model', 65000, 0, 0], - ['In Refinement', '3 - In Refinement', 65000, 0, 0], - ['Comp Chem Ready!', '4 - CompChem ready', 65000, 0, 0], - ['Ready for Deposition!', '5 - Deposition ready', 65000, 0, 0], - ['In PDB', '6 - Deposited', 65000, 0, 0]] - - self.ligand_confidence_category = [ '0 - no ligand present', - '1 - Low Confidence', - '2 - Correct ligand, weak density', - '3 - Clear density, unexpected ligand', - '4 - High Confidence' ] - - self.ligand_site_information = self.db.get_list_of_pandda_sites_for_coot() - - - # this decides which samples will be looked at - self.selection_mode = '' -# self.selected_site='' - self.pandda_index=-1 # refers to the number of sites - self.site_index='0' - self.event_index='0' - - # the Folder is kind of a legacy thing because my inital idea was to have separate folders - # for Data Processing and Refinement - self.project_directory = self.settings['initial_model_directory'] - self.Serial=0 - self.Refine=None - self.index = -1 - self.Todo=[] - self.siteDict={} - - self.xtalID='' - self.compoundID='' - self.spider_plot='' - self.ligand_confidence='' - self.refinement_folder='' -# self.datasetOutcome='' - - self.pdb_style='refine.pdb' - self.mtz_style='refine.mtz' - - # stores imol of currently loaded molecules and maps - self.mol_dict = { 'protein': -1, - 'ligand': -1, - '2fofc': -1, - 'fofc': -1, - 'event': -1 } - - # two dictionaries which are flushed when a new crystal is loaded - # and which contain information to update the data source if necessary - self.db_dict_mainTable={} - self.db_dict_panddaTable={} - - ########################################################################################### - # some COOT settings - coot.set_map_radius(15) - coot.set_colour_map_rotation_for_map(0) - coot.set_colour_map_rotation_on_read_pdb_flag(0) - - self.QualityIndicators = { 'RefinementRcryst': '-', - 'RefinementRfree': '-', - 'RefinementRfreeTraficLight': 'gray', - 'RefinementResolution': '-', - 'RefinementResolutionTL': 'gray', - 'RefinementMolProbityScore': '-', - 'RefinementMolProbityScoreTL': 'gray', - 'RefinementRamachandranOutliers': '-', - 'RefinementRamachandranOutliersTL': 'gray', - 'RefinementRamachandranFavored': '-', - 'RefinementRamachandranFavoredTL': 'gray', - 'RefinementRmsdBonds': '-', - 'RefinementRmsdBondsTL': 'gray', - 'RefinementRmsdAngles': '-', - 'RefinementRmsdAnglesTL': 'gray', - 'RefinementMatrixWeight': '-' } - - self.spider_plot_data = { 'PANDDA_site_ligand_id': '-', - 'PANDDA_site_occupancy': '-', - 'PANDDA_site_B_average': '-', - 'PANDDA_site_B_ratio_residue_surroundings': '-', - 'PANDDA_site_RSCC': '-', - 'PANDDA_site_rmsd': '-', - 'PANDDA_site_RSR': '-', - 'PANDDA_site_RSZD': '-' } - - - # default refmac parameters - self.RefmacParams={ 'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': '' } - - - - def StartGUI(self): - - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_default_size(400, 800) - self.window.set_title("XChemExplorer") - self.vbox = gtk.VBox() # this is the main container - - ################################################################################# - # --- Sample Selection --- -# self.vbox.add(gtk.Label('Select Samples')) - - frame = gtk.Frame(label='Select Samples') - self.hbox_select_samples=gtk.HBox() -# vbox=gtk.VBox() - - self.cb_select_samples = gtk.combo_box_new_text() - self.cb_select_samples.connect("changed", self.set_selection_mode) - for citeria in self.selection_criteria: - self.cb_select_samples.append_text(citeria) - self.hbox_select_samples.add(self.cb_select_samples) - -# self.cb_select_sites = gtk.combo_box_new_text() -# self.cb_select_sites.connect("changed", self.set_site) -# for site in self.ligand_site_information: -# self.cb_select_sites.append_text(str(site[0])+' - '+str(site[1])) -# self.hbox_select_samples.add(self.cb_select_sites) - - self.select_samples_button = gtk.Button(label="GO") - self.select_samples_button.connect("clicked",self.get_samples_to_look_at) - self.hbox_select_samples.add(self.select_samples_button) - frame.add(self.hbox_select_samples) - self.vbox.pack_start(frame) - - ################################################################################# - # --- status window --- - frame=gtk.Frame() - self.status_label=gtk.Label() - frame.add(self.status_label) - self.vbox.pack_start(frame) - - - # SPACER - self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- Refinement Statistics --- - # next comes a section which displays some global quality indicators - # a combination of labels and textview widgets, arranged in a table - - RRfreeLabel_frame=gtk.Frame() - self.RRfreeLabel = gtk.Label('R/Rfree') - RRfreeLabel_frame.add(self.RRfreeLabel) - self.RRfreeValue = gtk.Label(self.QualityIndicators['RefinementRcryst']+'/'+self.QualityIndicators['RefinementRfree']) - RRfreeBox_frame=gtk.Frame() - self.RRfreeBox = gtk.EventBox() - self.RRfreeBox.add(self.RRfreeValue) - RRfreeBox_frame.add(self.RRfreeBox) - - ResolutionLabel_frame=gtk.Frame() - self.ResolutionLabel = gtk.Label('Resolution') - ResolutionLabel_frame.add(self.ResolutionLabel) - self.ResolutionValue = gtk.Label(self.QualityIndicators['RefinementResolution']) - ResolutionBox_frame=gtk.Frame() - self.ResolutionBox = gtk.EventBox() - self.ResolutionBox.add(self.ResolutionValue) - ResolutionBox_frame.add(self.ResolutionBox) - - MolprobityScoreLabel_frame=gtk.Frame() - self.MolprobityScoreLabel = gtk.Label('MolprobityScore') - MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) - self.MolprobityScoreValue = gtk.Label(self.QualityIndicators['RefinementMolProbityScore']) - MolprobityScoreBox_frame=gtk.Frame() - self.MolprobityScoreBox = gtk.EventBox() - self.MolprobityScoreBox.add(self.MolprobityScoreValue) - MolprobityScoreBox_frame.add(self.MolprobityScoreBox) - - RamachandranOutliersLabel_frame=gtk.Frame() - self.RamachandranOutliersLabel = gtk.Label('Rama Outliers') - RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) - self.RamachandranOutliersValue = gtk.Label(self.QualityIndicators['RefinementRamachandranOutliers']) - RamachandranOutliersBox_frame=gtk.Frame() - self.RamachandranOutliersBox = gtk.EventBox() - self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) - RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) - - RamachandranFavoredLabel_frame=gtk.Frame() - self.RamachandranFavoredLabel = gtk.Label('Rama Favored') - RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) - self.RamachandranFavoredValue = gtk.Label(self.QualityIndicators['RefinementRamachandranFavored']) - RamachandranFavoredBox_frame=gtk.Frame() - self.RamachandranFavoredBox = gtk.EventBox() - self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) - RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) - - rmsdBondsLabel_frame=gtk.Frame() - self.rmsdBondsLabel = gtk.Label('rmsd(Bonds)') - rmsdBondsLabel_frame.add(self.rmsdBondsLabel) - self.rmsdBondsValue = gtk.Label(self.QualityIndicators['RefinementRmsdBonds']) - rmsdBondsBox_frame=gtk.Frame() - self.rmsdBondsBox = gtk.EventBox() - self.rmsdBondsBox.add(self.rmsdBondsValue) - rmsdBondsBox_frame.add(self.rmsdBondsBox) - - rmsdAnglesLabel_frame=gtk.Frame() - self.rmsdAnglesLabel = gtk.Label('rmsd(Angles)') - rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) - self.rmsdAnglesValue = gtk.Label(self.QualityIndicators['RefinementRmsdAngles']) - rmsdAnglesBox_frame=gtk.Frame() - self.rmsdAnglesBox = gtk.EventBox() - self.rmsdAnglesBox.add(self.rmsdAnglesValue) - rmsdAnglesBox_frame.add(self.rmsdAnglesBox) - - MatrixWeightLabel_frame=gtk.Frame() - self.MatrixWeightLabel = gtk.Label('Matrix Weight') - MatrixWeightLabel_frame.add(self.MatrixWeightLabel) - self.MatrixWeightValue = gtk.Label(self.QualityIndicators['RefinementMatrixWeight']) - MatrixWeightBox_frame=gtk.Frame() - self.MatrixWeightBox = gtk.EventBox() - self.MatrixWeightBox.add(self.MatrixWeightValue) - MatrixWeightBox_frame.add(self.MatrixWeightBox) - - ligandIDLabel_frame=gtk.Frame() - self.ligandIDLabel = gtk.Label('Ligand ID') - ligandIDLabel_frame.add(self.ligandIDLabel) - self.ligandIDValue = gtk.Label(self.spider_plot_data['PANDDA_site_ligand_id']) - ligandIDBox_frame=gtk.Frame() - self.ligandIDBox = gtk.EventBox() - self.ligandIDBox.add(self.ligandIDValue) - ligandIDBox_frame.add(self.ligandIDBox) - - ligand_occupancyLabel_frame=gtk.Frame() - self.ligand_occupancyLabel = gtk.Label('occupancy') - ligand_occupancyLabel_frame.add(self.ligand_occupancyLabel) - self.ligand_occupancyValue = gtk.Label(self.spider_plot_data['PANDDA_site_occupancy']) - ligand_occupancyBox_frame=gtk.Frame() - self.ligand_occupancyBox = gtk.EventBox() - self.ligand_occupancyBox.add(self.ligand_occupancyValue) - ligand_occupancyBox_frame.add(self.ligand_occupancyBox) - - ligand_BaverageLabel_frame=gtk.Frame() - self.ligand_BaverageLabel = gtk.Label('B average') - ligand_BaverageLabel_frame.add(self.ligand_BaverageLabel) - self.ligand_BaverageValue = gtk.Label(self.spider_plot_data['PANDDA_site_B_average']) - ligand_BaverageBox_frame=gtk.Frame() - self.ligand_BaverageBox = gtk.EventBox() - self.ligand_BaverageBox.add(self.ligand_BaverageValue) - ligand_BaverageBox_frame.add(self.ligand_BaverageBox) - - ligand_BratioSurroundingsLabel_frame=gtk.Frame() - self.ligand_BratioSurroundingsLabel = gtk.Label('B ratio') - ligand_BratioSurroundingsLabel_frame.add(self.ligand_BratioSurroundingsLabel) - self.ligand_BratioSurroundingsValue = gtk.Label(self.spider_plot_data['PANDDA_site_B_ratio_residue_surroundings']) - ligand_BratioSurroundingsBox_frame=gtk.Frame() - self.ligand_BratioSurroundingsBox = gtk.EventBox() - self.ligand_BratioSurroundingsBox.add(self.ligand_BratioSurroundingsValue) - ligand_BratioSurroundingsBox_frame.add(self.ligand_BratioSurroundingsBox) - - ligand_RSCCLabel_frame=gtk.Frame() - self.ligand_RSCCLabel = gtk.Label('RSCC') - ligand_RSCCLabel_frame.add(self.ligand_RSCCLabel) - self.ligand_RSCCValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSCC']) - ligand_RSCCBox_frame=gtk.Frame() - self.ligand_RSCCBox = gtk.EventBox() - self.ligand_RSCCBox.add(self.ligand_RSCCValue) - ligand_RSCCBox_frame.add(self.ligand_RSCCBox) - - ligand_rmsdLabel_frame=gtk.Frame() - self.ligand_rmsdLabel = gtk.Label('rmsd') - ligand_rmsdLabel_frame.add(self.ligand_rmsdLabel) - self.ligand_rmsdValue = gtk.Label(self.spider_plot_data['PANDDA_site_rmsd']) - ligand_rmsdBox_frame=gtk.Frame() - self.ligand_rmsdBox = gtk.EventBox() - self.ligand_rmsdBox.add(self.ligand_rmsdValue) - ligand_rmsdBox_frame.add(self.ligand_rmsdBox) - - ligand_RSRLabel_frame=gtk.Frame() - self.ligand_RSRLabel = gtk.Label('RSR') - ligand_RSRLabel_frame.add(self.ligand_RSRLabel) - self.ligand_RSRValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSR']) - ligand_RSRBox_frame=gtk.Frame() - self.ligand_RSRBox = gtk.EventBox() - self.ligand_RSRBox.add(self.ligand_RSRValue) - ligand_RSRBox_frame.add(self.ligand_RSRBox) - - ligand_RSZDLabel_frame=gtk.Frame() - self.ligand_RSZDLabel = gtk.Label('RSZD') - ligand_RSZDLabel_frame.add(self.ligand_RSZDLabel) - self.ligand_RSZDValue = gtk.Label(self.spider_plot_data['PANDDA_site_RSZD']) - ligand_RSZDBox_frame=gtk.Frame() - self.ligand_RSZDBox = gtk.EventBox() - self.ligand_RSZDBox.add(self.ligand_RSZDValue) - ligand_RSZDBox_frame.add(self.ligand_RSZDBox) - - outer_frame = gtk.Frame() - hbox = gtk.HBox() - - frame = gtk.Frame() - self.table_left = gtk.Table(8, 2, False) - self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) - self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) - self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) - self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) - self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) - self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) - self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) - self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) - self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) - self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) - self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) - self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) - self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) - self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) - self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) - self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) - frame.add(self.table_left) - hbox.add(frame) - - frame=gtk.Frame() - self.table_right = gtk.Table(8, 2, False) - self.table_right.attach(ligandIDLabel_frame, 0, 1, 0, 1) - self.table_right.attach(ligand_occupancyLabel_frame, 0, 1, 1, 2) - self.table_right.attach(ligand_BaverageLabel_frame, 0, 1, 2, 3) - self.table_right.attach(ligand_BratioSurroundingsLabel_frame, 0, 1, 3, 4) - self.table_right.attach(ligand_RSCCLabel_frame, 0, 1, 4, 5) - self.table_right.attach(ligand_rmsdLabel_frame, 0, 1, 5, 6) - self.table_right.attach(ligand_RSRLabel_frame, 0, 1, 6, 7) - self.table_right.attach(ligand_RSZDLabel_frame, 0, 1, 7, 8) - self.table_right.attach(ligandIDBox_frame, 1, 2, 0, 1) - self.table_right.attach(ligand_occupancyBox_frame, 1, 2, 1, 2) - self.table_right.attach(ligand_BaverageBox_frame, 1, 2, 2, 3) - self.table_right.attach(ligand_BratioSurroundingsBox_frame, 1, 2, 3, 4) - self.table_right.attach(ligand_RSCCBox_frame, 1, 2, 4, 5) - self.table_right.attach(ligand_rmsdBox_frame, 1, 2, 5, 6) - self.table_right.attach(ligand_RSRBox_frame, 1, 2, 6, 7) - self.table_right.attach(ligand_RSZDBox_frame, 1, 2, 7, 8) - frame.add(self.table_right) - hbox.add(frame) - - outer_frame.add(hbox) - self.vbox.add(outer_frame) - - button = gtk.Button(label="Show MolProbity to-do list") - button.connect("clicked",self.show_molprobity_to_do) - self.vbox.add(button) - self.vbox.pack_start(frame) - - - # SPACER - self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- hbox for compound picture & spider_plot (formerly: refinement history) --- - frame=gtk.Frame() - self.hbox_for_info_graphics=gtk.HBox() - - # --- compound picture --- - compound_frame=gtk.Frame() - pic = gtk.gdk.pixbuf_new_from_file(os.path.join(os.getenv('XChemExplorer_DIR'),'image','NO_COMPOUND_IMAGE_AVAILABLE.png')) - self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.image = gtk.Image() - self.image.set_from_pixbuf(self.pic) - compound_frame.add(self.image) - self.hbox_for_info_graphics.add(compound_frame) - - # --- Refinement History --- -# self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) -# self.canvas.set_size_request(190, 190) -# self.hbox_for_info_graphics.add(self.canvas) - - # --- Spider Plot --- - spider_plot_frame=gtk.Frame() - spider_plot_pic = gtk.gdk.pixbuf_new_from_file(os.path.join(os.getenv('XChemExplorer_DIR'),'image','NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image = gtk.Image() - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - spider_plot_frame.add(self.spider_plot_image) - self.hbox_for_info_graphics.add(spider_plot_frame) - - frame.add(self.hbox_for_info_graphics) - self.vbox.add(frame) - - - - ################################################################################# - # --- pandda.inspect user comments --- - outer_frame = gtk.Frame(label='pandda.inspect comments') - vbox=gtk.VBox() - ligand_site_name_label_frame = gtk.Frame() - ligand_site_name_label = gtk.Label('Site Name') - ligand_site_name_label_frame.add(ligand_site_name_label) - ligand_inspect_confidence_label_frame = gtk.Frame() - ligand_inspect_confidence_label = gtk.Label('Confidence') - ligand_inspect_confidence_label_frame.add(ligand_inspect_confidence_label) - ligand_inspect_interesting_label_frame = gtk.Frame() - ligand_inspect_interesting_label = gtk.Label('Interesting') - ligand_inspect_interesting_label_frame.add(ligand_inspect_interesting_label) - ligand_inspect_comment_label_frame = gtk.Frame() - ligand_inspect_comment_label = gtk.Label('Comment') - ligand_inspect_comment_label_frame.add(ligand_inspect_comment_label) - ligand_site_name_value_frame = gtk.Frame() - self.ligand_site_name_value = gtk.Label('-') - ligand_site_name_value_frame.add(self.ligand_site_name_value) - ligand_inspect_confidence_value_frame = gtk.Frame() - self.ligand_inspect_confidence_value = gtk.Label('-') - ligand_inspect_confidence_value_frame.add(self.ligand_inspect_confidence_value) - ligand_inspect_interesting_value_frame = gtk.Frame() - self.ligand_inspect_interesting_value = gtk.Label('-') - ligand_inspect_interesting_value_frame.add(self.ligand_inspect_interesting_value) - ligand_inspect_comment_value_frame = gtk.Frame() - self.ligand_inspect_comment_value = gtk.Label('-') - ligand_inspect_comment_value_frame.add(self.ligand_inspect_comment_value) - - frame_pandda_inspect_comments_table = gtk.Frame() - pandda_inspect_comments_table = gtk.Table(2, 6, False) - pandda_inspect_comments_table.attach(ligand_site_name_label_frame, 0,1,0,1) - pandda_inspect_comments_table.attach(ligand_site_name_value_frame, 1,2,0,1) - pandda_inspect_comments_table.attach(ligand_inspect_confidence_label_frame, 2,3,0,1) - pandda_inspect_comments_table.attach(ligand_inspect_confidence_value_frame, 3,4,0,1) - pandda_inspect_comments_table.attach(ligand_inspect_interesting_label_frame, 4,5,0,1) - pandda_inspect_comments_table.attach(ligand_inspect_interesting_value_frame, 5,6,0,1) - pandda_inspect_comments_table.attach(ligand_inspect_comment_label_frame, 0,1,1,2) - pandda_inspect_comments_table.attach(ligand_inspect_comment_value_frame, 1,6,1,2) - - frame_pandda_inspect_comments_table.add(pandda_inspect_comments_table) - vbox.add(frame_pandda_inspect_comments_table) - outer_frame.add(vbox) - self.vbox.pack_start(outer_frame) - -# # SPACER - self.vbox.add(gtk.Label(' ')) - - ################################################################################# - outer_frame = gtk.Frame(label='Sample Navigator') - hboxSample=gtk.HBox() - - # --- crystal navigator combobox --- - frame = gtk.Frame() - self.vbox_sample_navigator=gtk.VBox() - self.cb = gtk.combo_box_new_text() - self.cb.connect("changed", self.ChooseXtal) - self.vbox_sample_navigator.add(self.cb) - # --- crystal navigator backward/forward button --- - self.PREVbutton = gtk.Button(label="<<<") - self.NEXTbutton = gtk.Button(label=">>>") - self.PREVbutton.connect("clicked", self.ChangeXtal,-1) - self.NEXTbutton.connect("clicked", self.ChangeXtal,+1) - hbox = gtk.HBox() - hbox.pack_start(self.PREVbutton) - hbox.pack_start(self.NEXTbutton) - self.vbox_sample_navigator.add(hbox) - frame.add(self.vbox_sample_navigator) - hboxSample.add(frame) - - # --- site navigator combobox --- - frame = gtk.Frame() - self.vbox_site_navigator=gtk.VBox() - self.cb_site = gtk.combo_box_new_text() - self.cb_site.connect("changed", self.ChooseSite) - self.vbox_site_navigator.add(self.cb_site) - # --- site navigator backward/forward button --- - self.PREVbuttonSite = gtk.Button(label="<<<") - self.NEXTbuttonSite = gtk.Button(label=">>>") - self.PREVbuttonSite.connect("clicked", self.ChangeSite,-1) - self.NEXTbuttonSite.connect("clicked", self.ChangeSite,+1) - hbox = gtk.HBox() - hbox.pack_start(self.PREVbuttonSite) - hbox.pack_start(self.NEXTbuttonSite) - self.vbox_site_navigator.add(hbox) - frame.add(self.vbox_site_navigator) - hboxSample.add(frame) - - outer_frame.add(hboxSample) - self.vbox.add(outer_frame) - - # SPACER - self.vbox.add(gtk.Label(' ')) - - ################################################################################# - # --- current refinement stage --- - outer_frame=gtk.Frame() - hbox=gtk.HBox() - - frame = gtk.Frame(label='Analysis Status') - vbox=gtk.VBox() - self.experiment_stage_button_list=[] - for n,button in enumerate(self.experiment_stage): - if n == 0: - new_button = gtk.RadioButton(None, button[0]) - else: - new_button = gtk.RadioButton(new_button, button[0]) - new_button.connect("toggled",self.experiment_stage_button_clicked,button[1]) - vbox.add(new_button) - self.experiment_stage_button_list.append(new_button) - frame.add(vbox) - hbox.pack_start(frame) - - # --- ligand confidence --- - frame = gtk.Frame(label='Ligand Confidence') - vbox=gtk.VBox() - self.ligand_confidence_button_list=[] - for n,criteria in enumerate(self.ligand_confidence_category): - if n == 0: - new_button = gtk.RadioButton(None, criteria) - else: - new_button = gtk.RadioButton(new_button, criteria) - new_button.connect("toggled",self.ligand_confidence_button_clicked,criteria) - vbox.add(new_button) - self.ligand_confidence_button_list.append(new_button) - frame.add(vbox) - hbox.pack_start(frame) - - outer_frame.add(hbox) - self.vbox.pack_start(outer_frame) - - # SPACER - self.vbox.add(gtk.Label(' ')) - - # --- ligand modeling --- - frame = gtk.Frame(label='Ligand Modeling') - self.hbox_for_modeling=gtk.HBox() - self.merge_ligand_button=gtk.Button(label="Merge Ligand") - self.place_ligand_here_button=gtk.Button(label="Place Ligand here") - self.hbox_for_modeling.add(self.place_ligand_here_button) - self.place_ligand_here_button.connect("clicked",self.place_ligand_here) - self.hbox_for_modeling.add(self.merge_ligand_button) - self.merge_ligand_button.connect("clicked",self.merge_ligand_into_protein) - frame.add(self.hbox_for_modeling) - self.vbox.pack_start(frame) - - -# # --- ligand confidence --- -# self.cb_ligand_confidence = gtk.combo_box_new_text() -# self.cb_ligand_confidence.connect("changed", self.set_ligand_confidence) -# for citeria in self.ligand_confidence: -# self.cb_ligand_confidence.append_text(citeria) -# self.vbox.add(self.cb_ligand_confidence) - - - # --- refinement & options --- - self.hbox_for_refinement=gtk.HBox() - self.REFINEbutton = gtk.Button(label="Refine") - self.RefinementParamsButton = gtk.Button(label="refinement parameters") - self.REFINEbutton.connect("clicked",self.REFINE) - self.hbox_for_refinement.add(self.REFINEbutton) - self.RefinementParamsButton.connect("clicked",self.RefinementParams) - self.hbox_for_refinement.add(self.RefinementParamsButton) - self.vbox.add(self.hbox_for_refinement) - -# self.VALIDATEbutton = gtk.Button(label="validate structure") -# self.DEPOSITbutton = gtk.Button(label="prepare for deposition") - - - # --- CANCEL button --- - self.CANCELbutton = gtk.Button(label="CANCEL") - self.CANCELbutton.connect("clicked", self.CANCEL) - self.vbox.add(self.CANCELbutton) - - self.window.add(self.vbox) - self.window.show_all() - - def CANCEL(self,widget): - self.window.destroy() - - - def ChangeXtal(self,widget,data=None): - self.index = self.index + data - if self.index < 0: - self.index = 0 - if self.index >= len(self.Todo): -# self.index = len(self.Todo) - self.index = 0 - self.cb.set_active(self.index) - - def ChooseXtal(self, widget): - self.xtalID = str(widget.get_active_text()) - for n,item in enumerate(self.Todo): - if str(item[0]) == self.xtalID: - self.index = n - self.merge_ligand_button.set_sensitive(True) - self.place_ligand_here_button.set_sensitive(True) - - self.ligand_site_name_value.set_label('-') - self.ligand_inspect_confidence_value.set_label('-') - self.ligand_inspect_interesting_value.set_label('-') - self.ligand_inspect_comment_value.set_label('-') - - self.refresh_site_combobox() - self.db_dict_mainTable={} - self.db_dict_panddaTable={} - if str(self.Todo[self.index][0]) is not None: - self.compoundID=str(self.Todo[self.index][1]) - self.refinement_folder=str(self.Todo[self.index][4]) - self.refinement_outcome=str(self.Todo[self.index][5]) - self.update_RefinementOutcome_radiobutton() - if self.xtalID not in self.siteDict: # i.e. we are not working with a PanDDA model - self.ligand_confidence=str(self.Todo[self.index][6]) - self.update_LigandConfidence_radiobutton() - - self.RefreshData() - - - def update_RefinementOutcome_radiobutton(self): - # updating dataset outcome radiobuttons - current_stage=0 - for i,entry in enumerate(self.experiment_stage): - if entry[1].split()[0] == self.refinement_outcome.split()[0]: - current_stage=i - break - for i,button in enumerate(self.experiment_stage_button_list): - if i==current_stage: - button.set_active(True) - break - - def update_LigandConfidence_radiobutton(self): - # updating ligand confidence radiobuttons - current_stage=0 - for i,entry in enumerate(self.ligand_confidence_category): - print '--->',entry,self.ligand_confidence - try: - if entry.split()[0] == self.ligand_confidence.split()[0]: - current_stage=i - break - except IndexError: - pass - for i,button in enumerate(self.ligand_confidence_button_list): - if i==current_stage: - button.set_active(True) - break - - - def refresh_site_combobox(self): - # reset self.pandda_index - self.pandda_index=-1 - # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever be 100 sites - for n in range(-1,100): - self.cb_site.remove_text(0) - self.site_index='0' - self.event_index='0' - # only repopulate if site exists - if self.xtalID in self.siteDict: - for item in sorted(self.siteDict[self.xtalID]): - self.cb_site.append_text('site: %s - event: %s' %(item[5],item[6])) - - def ChangeSite(self, widget,data=None): - if self.xtalID in self.siteDict: - self.pandda_index = self.pandda_index + data - if self.pandda_index < 0: - self.pandda_index=0 - if self.pandda_index >= len(self.siteDict[self.xtalID]): - self.pandda_index=0 - self.cb_site.set_active(self.pandda_index) - - def ChooseSite(self, widget): - tmp=str(widget.get_active_text()) - self.site_index=tmp.split()[1] - self.event_index=tmp.split()[4] - for n,item in enumerate(self.siteDict[self.xtalID]): - if item[5]==self.site_index and item[6]==self.event_index: - self.pandda_index = n - self.RefreshSiteData() - - def RefreshSiteData(self): - - if self.pandda_index == -1: - self.merge_ligand_button.set_sensitive(True) - self.place_ligand_here_button.set_sensitive(True) - else: - self.merge_ligand_button.set_sensitive(False) - self.place_ligand_here_button.set_sensitive(False) - # and remove ligand molecule so that there is no temptation to merge it - if len(coot_utils_XChem.molecule_number_list()) > 0: - for imol in coot_utils_XChem.molecule_number_list(): - if self.compoundID+'.pdb' in coot.molecule_name(imol): - coot.close_molecule(imol) - - - print 'pandda index',self.pandda_index - self.spider_plot=self.siteDict[self.xtalID][self.pandda_index][4] - print 'new spider plot:',self.spider_plot - self.event_map=self.siteDict[self.xtalID][self.pandda_index][0] - print 'new event map:',self.event_map - self.ligand_confidence=str(self.siteDict[self.xtalID][self.pandda_index][7]) - self.update_LigandConfidence_radiobutton() - site_x=float(self.siteDict[self.xtalID][self.pandda_index][1]) - site_y=float(self.siteDict[self.xtalID][self.pandda_index][2]) - site_z=float(self.siteDict[self.xtalID][self.pandda_index][3]) - print 'new site coordinates:',site_x,site_y,site_z - coot.set_rotation_centre(site_x,site_y,site_z) - - self.ligand_site_name_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][8])) - self.ligand_inspect_confidence_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][9])) - self.ligand_inspect_interesting_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][10])) - self.ligand_inspect_comment_value.set_label(str(self.siteDict[self.xtalID][self.pandda_index][11])) - - self.spider_plot_data=self.db.get_db_pandda_dict_for_sample_and_site_and_event(self.xtalID,self.site_index,self.event_index) - print '>>>>> spider plot data',self.spider_plot_data - self.ligandIDValue.set_label(self.spider_plot_data['PANDDA_site_ligand_id']) - try: - self.ligand_occupancyValue.set_label( str(round(float(self.spider_plot_data['PANDDA_site_occupancy']),2)) ) - except ValueError: - self.ligand_occupancyValue.set_label('-') - - try: - self.ligand_BaverageValue.set_label( str(round(float(self.spider_plot_data['PANDDA_site_B_average']),2)) ) - except ValueError: - self.ligand_BaverageValue.set_label('-') - - try: - self.ligand_BratioSurroundingsValue.set_label( str(round(float(self.spider_plot_data['PANDDA_site_B_ratio_residue_surroundings']),2)) ) - except ValueError: - self.ligand_BratioSurroundingsValue.set_label('-') - - try: - self.ligand_RSCCValue.set_label( str(round(float(self.spider_plot_data['PANDDA_site_RSCC']),2)) ) - except ValueError: - self.ligand_RSCCValue.set_label('-') - - try: - self.ligand_rmsdValue.set_label( str(round(float(self.spider_plot_data['PANDDA_site_rmsd']),2)) ) - except ValueError: - self.ligand_rmsdValue.set_label('-') - - try: - self.ligand_RSRValue.set_label( str(round(float(self.spider_plot_data['PANDDA_site_RSR']),2)) ) - except ValueError: - self.ligand_RSRValue.set_label('-') - - try: - self.ligand_RSZDValue.set_label( str(round(float(self.spider_plot_data['PANDDA_site_RSZD']),2)) ) - except ValueError: - self.ligand_RSZDValue.set_label('-') - - ######################################################################################### - # delete old Event MAPs - if len(coot_utils_XChem.molecule_number_list()) > 0: - for imol in coot_utils_XChem.molecule_number_list(): - if 'map.native.ccp4' in coot.molecule_name(imol): - coot.close_molecule(imol) - - ######################################################################################### - # Spider plot - # Note: refinement history was shown instead previously - if os.path.isfile(self.spider_plot): - spider_plot_pic = gtk.gdk.pixbuf_new_from_file(self.spider_plot) - else: - spider_plot_pic = gtk.gdk.pixbuf_new_from_file(os.path.join(os.getenv('XChemExplorer_DIR'),'image','NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = spider_plot_pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - - ######################################################################################### - # check for PANDDAs EVENT maps - if os.path.isfile(self.event_map): - coot.handle_read_ccp4_map((self.event_map),0) - for imol in coot_utils_XChem.molecule_number_list(): - if self.event_map in coot.molecule_name(imol): - coot.set_contour_level_in_sigma(imol,2) -# coot.set_contour_level_absolute(imol,0.5) -# coot.set_last_map_colour(0.4,0,0.4) - coot.set_last_map_colour(0.74,0.44,0.02) - - - - def experiment_stage_button_clicked(self,widget, data=None): - self.db_dict_mainTable['RefinementOutcome']=data - print '==> XCE: setting Refinement Outcome for '+self.xtalID+' to '+str(data)+' in mainTable of datasource' - self.db.update_data_source(self.xtalID,self.db_dict_mainTable) - - - def ligand_confidence_button_clicked(self,widget,data=None): - print 'PANDDA_index',self.pandda_index - if self.pandda_index == -1: - self.db_dict_mainTable['RefinementLigandConfidence']=data - print '==> XCE: setting Ligand Confidence for '+self.xtalID+' to '+str(data)+' in mainTable of datasource' - self.db.update_data_source(self.xtalID,self.db_dict_mainTable) - self.Todo[self.index][6]=data - else: - self.db_dict_panddaTable['PANDDA_site_confidence']=data - print '==> XCE: setting Ligand Confidence for '+self.xtalID+' (site='+str(self.site_index)+', event='+str(self.event_index)+') to '+str(data)+' in panddaTable of datasource' - self.db.update_site_event_panddaTable(self.xtalID,self.site_index,self.event_index,self.db_dict_panddaTable) - self.siteDict[self.xtalID][self.pandda_index][7]=data - - def RefreshData(self): - # reset spider plot image - spider_plot_pic = gtk.gdk.pixbuf_new_from_file(os.path.join(os.getenv('XChemExplorer_DIR'),'image','NO_SPIDER_PLOT_AVAILABLE.png')) - self.spider_plot_pic = spider_plot_pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.spider_plot_image.set_from_pixbuf(self.spider_plot_pic) - - # initialize Refinement library - self.Refine=XChemRefine.RefineOld(self.project_directory,self.xtalID,self.compoundID,self.data_source) - self.Serial=self.Refine.GetSerial() - if self.Serial==1: - # i.e. no refinement has been done; data is probably straight out of dimple - if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.pdb_style)): - print '==> XCE: updating quality indicators in data source for '+self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID,self.data_source,os.path.join(self.project_directory,self.xtalID,self.pdb_style)) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID,self.data_source,'') # '' because file does not exist - elif os.path.isfile(os.path.join(self.project_directory,self.xtalID,'dimple.pdb')): - print '==> XCE: updating quality indicators in data source for '+self.xtalID - XChemUtils.parse().update_datasource_with_PDBheader(self.xtalID,self.data_source,os.path.join(self.project_directory,self.xtalID,'dimple.pdb')) - XChemUtils.parse().update_datasource_with_phenix_validation_summary(self.xtalID,self.data_source,'') # '' because file does not exist - - # all this information is now updated in the datasource after each refinement cycle - self.QualityIndicators=self.db.get_db_dict_for_sample(self.xtalID) - - ######################################################################################### - # history - # if the structure was previously refined, try to read the parameters -# self.hbox_for_info_graphics.remove(self.canvas) - if self.Serial > 1: - self.RefmacParams=self.Refine.ParamsFromPreviousCycle(self.Serial-1) -# refinement_cycle,Rfree,Rcryst=self.Refine.GetRefinementHistory() -# self.canvas = FigureCanvas(self.update_plot(refinement_cycle,Rfree,Rcryst)) -# else: -# self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) # a gtk.DrawingArea -# self.canvas.set_size_request(190, 190) -# self.hbox_for_info_graphics.add(self.canvas) -# self.canvas.show() - - ######################################################################################### - # update pdb & maps - - ######################################################################################### - # delete old PDB and MAP files - # - get a list of all molecules which are currently opened in COOT - # - remove all molecules/ maps before loading a new set - if len(coot_utils_XChem.molecule_number_list()) > 0: - for item in coot_utils_XChem.molecule_number_list(): - coot.close_molecule(item) - - ######################################################################################### - # read new PDB files - # read protein molecule after ligand so that this one is the active molecule - coot.set_nomenclature_errors_on_read("ignore") - if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.compoundID+'.pdb')): - imol=coot.handle_read_draw_molecule_with_recentre(os.path.join(self.project_directory,self.xtalID,self.compoundID+'.pdb'),0) - self.mol_dict['ligand']=imol - coot.read_cif_dictionary(os.path.join(self.project_directory,self.xtalID,self.compoundID+'.cif')) - if not os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.pdb_style)): - os.chdir(os.path.join(self.project_directory,self.xtalID)) - # we want to be able to check dimple results immediately, but don't want to interfere with refinement -# if not os.path.isfile('REFINEMENT_IN_PROGRESS'): -# if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.xtalID+'-ensemble-model.pdb')): -# os.symlink(self.xtalID+'-ensemble-model.pdb',self.pdb_style) -# elif os.path.isfile(os.path.join(self.project_directory,self.xtalID,'dimple.pdb')): -# os.symlink('dimple.pdb',self.pdb_style) -# else: -# self.go_to_next_xtal() - if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.pdb_style)): - os.chdir(os.path.join(self.project_directory,self.xtalID)) - imol=coot.handle_read_draw_molecule_with_recentre(os.path.join(self.project_directory,self.xtalID,self.pdb_style),0) - elif os.path.isfile(os.path.join(self.project_directory,self.xtalID,'dimple.pdb')): - os.chdir(os.path.join(self.project_directory,self.xtalID)) - imol=coot.handle_read_draw_molecule_with_recentre(os.path.join(self.project_directory,self.xtalID,'dimple.pdb'),0) - else: - self.go_to_next_xtal() - self.mol_dict['protein']=imol - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith(self.pdb_style): - coot.set_show_symmetry_master(1) # master switch to show symmetry molecules - coot.set_show_symmetry_molecule(item,1) # show symm for model - - ######################################################################################### - # read fofo maps - # - read ccp4 map: 0 - 2fofc map, 1 - fofc.map - # read 2fofc map last so that one can change its contour level - if os.path.isfile(os.path.join(self.project_directory,self.xtalID,'2fofc.map')): - coot.set_default_initial_contour_level_for_difference_map(3) - coot.handle_read_ccp4_map(os.path.join(self.project_directory,self.xtalID,'fofc.map'),1) - coot.set_default_initial_contour_level_for_map(1) - coot.handle_read_ccp4_map(os.path.join(self.project_directory,self.xtalID,'2fofc.map'),0) - coot.set_last_map_colour(0,0,1) - else: - # try to open mtz file with same name as pdb file - coot.set_default_initial_contour_level_for_map(1) -# if not os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.mtz_style)): -# os.chdir(os.path.join(self.project_directory,self.xtalID)) -# if not os.path.isfile('REFINEMENT_IN_PROGRESS'): -# if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.xtalID+'-pandda-input.mtz')): -# os.symlink(self.xtalID+'-pandda-input.mtz',self.mtz_style) -# elif os.path.isfile(os.path.join(self.project_directory,self.xtalID,'dimple.mtz')): -# os.symlink('dimple.mtz',self.mtz_style) - if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.mtz_style)): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory,self.xtalID,self.mtz_style)) - elif os.path.isfile(os.path.join(self.project_directory,self.xtalID,'dimple.mtz')): - coot.auto_read_make_and_draw_maps(os.path.join(self.project_directory,self.xtalID,'dimple.mtz')) - - ######################################################################################### - # update Quality Indicator table - try: - self.RRfreeValue.set_label( str(round(float(self.QualityIndicators['RefinementRcryst']),3)) +' / '+str(round(float(self.QualityIndicators['RefinementRfree']),3))) - except ValueError: - self.RRfreeValue.set_label('-') - - try: - self.RRfreeBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RefinementRfreeTraficLight'])) - except ValueError: - pass - self.ResolutionValue.set_label(self.QualityIndicators['RefinementResolution']) - try: - self.ResolutionBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RefinementResolutionTL'])) - except ValueError: - pass - self.MolprobityScoreValue.set_label(self.QualityIndicators['RefinementMolProbityScore']) - try: - self.MolprobityScoreBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RefinementMolProbityScoreTL'])) - except ValueError: - pass - self.RamachandranOutliersValue.set_label(self.QualityIndicators['RefinementRamachandranOutliers']) - try: - self.RamachandranOutliersBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RefinementRamachandranOutliersTL'])) - except ValueError: - pass - self.RamachandranFavoredValue.set_label(self.QualityIndicators['RefinementRamachandranFavored']) - try: - self.RamachandranFavoredBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RefinementRamachandranFavoredTL'])) - except ValueError: - pass - self.rmsdBondsValue.set_label(self.QualityIndicators['RefinementRmsdBonds']) - try: - self.rmsdBondsBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RefinementRmsdBondsTL'])) - except ValueError: - pass - self.rmsdAnglesValue.set_label(self.QualityIndicators['RefinementRmsdAngles']) - try: - self.rmsdAnglesBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RefinementRmsdAnglesTL'])) - except ValueError: - pass - self.MatrixWeightValue.set_label(self.QualityIndicators['RefinementMatrixWeight']) - - try: - pic = gtk.gdk.pixbuf_new_from_file(os.path.join(self.project_directory,self.xtalID,self.compoundID+'.png')) - except gobject.GError: - pic = gtk.gdk.pixbuf_new_from_file(os.path.join(os.getenv('XChemExplorer_DIR'),'image','NO_COMPOUND_IMAGE_AVAILABLE.png')) - self.pic = pic.scale_simple(190, 190, gtk.gdk.INTERP_BILINEAR) - self.image.set_from_pixbuf(self.pic) - - def go_to_next_xtal(self): - self.index+=1 - if self.index >= len(self.Todo): - self.index = len(self.Todo) - self.cb.set_active(self.index) - - - def REFINE(self,widget): - - ####################################################### - # create folder for new refinement cycle - os.mkdir(os.path.join(self.project_directory,self.xtalID,'Refine_'+str(self.Serial))) - - ####################################################### - # write PDB file - # now take protein pdb file and write it to newly create Refine_ folder - # note: the user has to make sure that the ligand file was merged into main file - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith(self.pdb_style): - coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'Refine_'+str(self.Serial),'in.pdb')) - break - elif coot.molecule_name(item).endswith('dimple.pdb'): - coot.write_pdb_file(item,os.path.join(self.project_directory,self.xtalID,'Refine_'+str(self.Serial),'in.pdb')) - break - - - ####################################################### - # run REFMAC - self.Refine.RunRefmac(self.Serial,self.RefmacParams,self.external_software,self.xce_logfile) - - self.index+=1 - if self.index >= len(self.Todo): -# self.index = len(self.Todo) - self.index = 0 - self.cb.set_active(self.index) - - - def RefinementParams(self,widget): - print '\n==> XCE: changing refinement parameters' - self.RefmacParams=self.Refine.RefinementParams(self.RefmacParams) - - def set_selection_mode(self,widget): - self.selection_mode=widget.get_active_text() - - - def get_samples_to_look_at(self,widget): - if self.selection_mode=='': - self.status_label.set_text('select model stage') - return - self.status_label.set_text('checking datasource for samples... ') - # first remove old samples if present - if len(self.Todo) != 0: - for n,item in enumerate(self.Todo): - self.cb.remove_text(0) - self.Todo=[] - self.siteDict={} - self.Todo,self.siteDict=self.db.get_todoList_for_coot(self.selection_mode) - self.status_label.set_text('found %s samples' %len(self.Todo)) - # refresh sample CB - for item in sorted(self.Todo): - self.cb.append_text('%s' %item[0]) - if self.siteDict == {}: - self.cb_site.set_sensitive(False) - self.PREVbuttonSite.set_sensitive(False) - self.NEXTbuttonSite.set_sensitive(False) - else: - self.cb_site.set_sensitive(True) - self.PREVbuttonSite.set_sensitive(True) - self.NEXTbuttonSite.set_sensitive(True) - - - - - - def update_plot(self,refinement_cycle,Rfree,Rcryst): - fig = Figure(figsize=(2, 2), dpi=50) - Plot = fig.add_subplot(111) - Plot.set_ylim([0,max(Rcryst+Rfree)]) - Plot.set_xlabel('Refinement Cycle',fontsize=12) - Plot.plot(refinement_cycle,Rfree,label='Rfree',linewidth=2) - Plot.plot(refinement_cycle,Rcryst,label='Rcryst',linewidth=2) - Plot.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, - ncol=2, mode="expand", borderaxespad=0.,fontsize=12) - return fig - - def place_ligand_here(self,widget): - print '===> XCE: moving ligand to pointer' -# coot.move_molecule_here() - print 'LIGAND: ',self.mol_dict['ligand'] - coot_utils_XChem.move_molecule_here(self.mol_dict['ligand']) - - def merge_ligand_into_protein(self,widget): - print '===> XCE: merge ligand into protein structure' - # merge_molecules(list(imols), imol) e.g. merge_molecules([1],0) - coot.merge_molecules_py([self.mol_dict['ligand']],self.mol_dict['protein']) - print '===> XCE: deleting ligand molecule' - coot.close_molecule(self.mol_dict['ligand']) - - def show_molprobity_to_do(self,widget): - if os.path.isfile(os.path.join(self.project_directory,self.xtalID,'Refine_'+str(self.Serial-1),'molprobity_coot.py')): - print '==> XCE: running MolProbity Summary for',self.xtalID - coot.run_script(os.path.join(self.project_directory,self.xtalID,'Refine_'+str(self.Serial-1),'molprobity_coot.py')) - else: - print '==> XCE: cannot find '+os.path.join(self.project_directory,self.xtalID,'Refine_'+str(self.Serial-1),'molprobity_coot.py') - -# def fit_ligand(self,widget): -# print 'fit' - -if __name__=='__main__': - GUI().StartGUI() diff --git a/lib/XChemCootReference.py b/lib/XChemCootReference.py deleted file mode 100755 index 96412abb..00000000 --- a/lib/XChemCootReference.py +++ /dev/null @@ -1,705 +0,0 @@ -# last edited: 03/08/2017 - 15:00 - -import sys,glob -import os -import pickle -import time -import gtk -#import threading -#import gobject -#gtk.gdk.threads_init() - -from matplotlib.figure import Figure -from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas - -# XCE libraries -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -import XChemRefine -import XChemUtils -import XChemLog - -# libraries from COOT -#import pygtk, gtk, pango -import coot - -# had to adapt the original coot_utils.py file -# otherwise unable to import the original file without complaints about missing modules etc. -# modified file is now in $XChemExplorer_DIR/lib -import coot_utils_XChem - - -class GUI(object): - - """ - main class which opens the actual GUI - """ - - def __init__(self): - - ########################################################################################### - # read in settings file from XChemExplorer to set the relevant paths - self.settings = pickle.load(open(".xce_settings.pkl","rb")) - remote_qsub_submission=self.settings['remote_qsub'] - self.database_directory=self.settings['database_directory'] - self.xce_logfile=self.settings['xce_logfile'] - self.Logfile=XChemLog.updateLog(self.xce_logfile) - self.Logfile.insert('starting COOT gui for reference model refinement') - self.data_source=self.settings['data_source'] - - # checking for external software packages - self.external_software=XChemUtils.external_software(self.xce_logfile).check() - self.external_software['qsub_remote']=remote_qsub_submission - - # the Folder is kind of a legacy thing because my inital idea was to have separate folders - # for Data Processing and Refinement - self.reference_directory = self.settings['reference_directory'] - self.refinementDir = '' - self.Serial=0 - self.Refine=None - - self.xtalID='' - self.compoundID='' - self.spider_plot='' - self.refinement_folder='' - self.pdbFile='' - self.mtzFree='' - - self.pdb_style='refine.pdb' - self.mtz_style='refine.mtz' - - # stores imol of currently loaded molecules and maps - self.mol_dict = { 'protein': -1, - 'ligand': -1, - '2fofc': -1, - 'fofc': -1, - 'event': -1 } - - self.ground_state_map_List = [] - self.job_running=False - - ########################################################################################### - # some COOT settings - coot.set_map_radius(17) - coot.set_colour_map_rotation_for_map(0) -# coot.set_colour_map_rotation_on_read_pdb_flag(21) - - self.QualityIndicators = { 'Rcryst': '-', - 'Rfree': '-', - 'RfreeTL': 'gray', - 'ResolutionHigh': '-', - 'ResolutionColor': 'gray', - 'MolprobityScore': '-', - 'MolprobityScoreColor': 'gray', - 'RamachandranOutliers': '-', - 'RamachandranOutliersColor': 'gray', - 'RamachandranFavored': '-', - 'RamachandranFavoredColor': 'gray', - 'rmsdBonds': '-', - 'rmsdBondsTL': 'gray', - 'rmsdAngles': '-', - 'rmsdAnglesTL': 'gray', - 'MatrixWeight': '-' } - - # default refmac parameters - self.RefmacParams={ 'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': '' } - - - - def StartGUI(self): - - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_default_size(400, 800) - self.window.set_title("Reference Model Builder") - self.vbox = gtk.VBox() # this is the main container - - ################################################################################# - # --- PDB file selection --- - # checking for pdb files in reference directory - referenceFiles=[] - for files in glob.glob(os.path.join(self.reference_directory,'*-ground-state.pdb')): - pdbFile=files[files.rfind('/')+1:] - referenceFiles.append(pdbFile) - frame = gtk.Frame(label='Select PDB file') - hbox=gtk.HBox() - self.cb_select_pdb = gtk.combo_box_new_text() -# self.cb_select_pdb.connect("changed", self.set_selection_mode) - for pdbFile in referenceFiles: - self.cb_select_pdb.append_text(pdbFile) - hbox.add(self.cb_select_pdb) - frame.add(hbox) - self.vbox.pack_start(frame) - - self.load_pdb_file_button = gtk.Button(label="Load") -# self.load_pdb_file_button.connect("clicked",self.get_samples_to_look_at) - self.load_pdb_file_button.connect("clicked",self.load_pdb_file) - hbox.add(self.load_pdb_file_button) - frame.add(hbox) - self.vbox.pack_start(frame) - - # SPACER - self.vbox.add(gtk.Label(' ')) - - frame = gtk.Frame(label='MTZ file to refine against') - hbox=gtk.HBox() - self.mtzFree='' - self.mtzFree_label=gtk.Label() - hbox.add(self.mtzFree_label) - frame.add(hbox) - self.vbox.pack_start(frame) - - # SPACER - self.vbox.add(gtk.Label(' ')) - - frame = gtk.Frame(label='MTZ file after refinement') - hbox=gtk.HBox() - self.mtzRefine_label=gtk.Label() - hbox.add(self.mtzRefine_label) - frame.add(hbox) - self.vbox.pack_start(frame) - - - - # SPACER - self.vbox.add(gtk.Label(' \n ')) - - - ################################################################################# - # --- ground state mean map --- - # checking for ground state mean map in reference folder -# self.meanMaps = {} -# for dirs in glob.glob(os.path.join(self.reference_directory,'pandda_*')): -# panddaDir=dirs.split('/')[len(dirs.split('/'))-1] -# for files in glob.glob(os.path.join(dirs,'processed_datasets','*','*ground-state-mean-map.native.ccp4')): -# if os.path.isfile(files): -# self.meanMaps[panddaDir]=files -# break - -# frame = gtk.Frame(label='Load ground-state-mean-map files') -# hbox=gtk.HBox() -# self.cb_select_mean_map = gtk.combo_box_new_text() -# for item in self.meanMaps: -# self.cb_select_mean_map.append_text(item) -# hbox.add(self.cb_select_mean_map) -# self.load_ground_state_map_button = gtk.Button(label="Load") -# self.load_ground_state_map_button.connect("clicked",self.load_ground_state_map) -# hbox.add(self.load_ground_state_map_button) -# frame.add(hbox) -# self.vbox.pack_start(frame) - -# frame = gtk.Frame() -# hbox=gtk.HBox() -# self.cb_select_mean_map_by_resolution = gtk.combo_box_new_text() -# self.cb_select_mean_map_by_resolution.connect("changed", self.show_selected_mean_map) -# hbox.add(self.cb_select_mean_map_by_resolution) -## self.show_highres_ground_state_map_button = gtk.Button(label="Show Highest\nResolution Map") -## self.show_highres_ground_state_map_button.connect("clicked",self.show_highres_ground_state_map) -## hbox.add(self.show_highres_ground_state_map_button) -## self.show_all_ground_state_map_button = gtk.Button(label="Show All Maps") -## self.show_all_ground_state_map_button.connect("clicked",self.show_all_ground_state_map) -## hbox.add(self.show_all_ground_state_map_button) -# frame.add(hbox) -# self.vbox.pack_start(frame) - - # SPACER -# self.vbox.add(gtk.Label(' \n ')) - - ################################################################################# - # --- Refinement History --- - frame = gtk.Frame(label='Refinement History') - self.hbox_for_info_graphics=gtk.HBox() - self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) - self.canvas.set_size_request(190, 190) - self.hbox_for_info_graphics.add(self.canvas) - frame.add(self.hbox_for_info_graphics) - self.vbox.pack_start(frame) - - ################################################################################# - # --- status window --- - frame=gtk.Frame(label='Status') - vbox=gtk.VBox() - self.spinnerBox=gtk.VBox() - self.refinementRunning=gtk.Spinner() - vbox.add(self.spinnerBox) -# hbox.add(self.refinementRunning) - self.status_label=gtk.Label() - vbox.add(self.status_label) - frame.add(vbox) - self.status_label.set_text('idle') - -# frame.add(self.status_label) - self.vbox.pack_start(frame) - - ################################################################################# - # --- Refinement Statistics --- - # next comes a section which displays some global quality indicators - # a combination of labels and textview widgets, arranged in a table - - RRfreeLabel_frame=gtk.Frame() - self.RRfreeLabel = gtk.Label('R/Rfree') - RRfreeLabel_frame.add(self.RRfreeLabel) - self.RRfreeValue = gtk.Label(self.QualityIndicators['Rcryst']+'/'+self.QualityIndicators['Rfree']) - RRfreeBox_frame=gtk.Frame() - self.RRfreeBox = gtk.EventBox() - self.RRfreeBox.add(self.RRfreeValue) - RRfreeBox_frame.add(self.RRfreeBox) - - ResolutionLabel_frame=gtk.Frame() - self.ResolutionLabel = gtk.Label('Resolution') - ResolutionLabel_frame.add(self.ResolutionLabel) - self.ResolutionValue = gtk.Label(self.QualityIndicators['ResolutionHigh']) - ResolutionBox_frame=gtk.Frame() - self.ResolutionBox = gtk.EventBox() - self.ResolutionBox.add(self.ResolutionValue) - ResolutionBox_frame.add(self.ResolutionBox) - - MolprobityScoreLabel_frame=gtk.Frame() - self.MolprobityScoreLabel = gtk.Label('MolprobityScore') - MolprobityScoreLabel_frame.add(self.MolprobityScoreLabel) - self.MolprobityScoreValue = gtk.Label(self.QualityIndicators['MolprobityScore']) - MolprobityScoreBox_frame=gtk.Frame() - self.MolprobityScoreBox = gtk.EventBox() - self.MolprobityScoreBox.add(self.MolprobityScoreValue) - MolprobityScoreBox_frame.add(self.MolprobityScoreBox) - - RamachandranOutliersLabel_frame=gtk.Frame() - self.RamachandranOutliersLabel = gtk.Label('Rama Outliers') - RamachandranOutliersLabel_frame.add(self.RamachandranOutliersLabel) - self.RamachandranOutliersValue = gtk.Label(self.QualityIndicators['RamachandranOutliers']) - RamachandranOutliersBox_frame=gtk.Frame() - self.RamachandranOutliersBox = gtk.EventBox() - self.RamachandranOutliersBox.add(self.RamachandranOutliersValue) - RamachandranOutliersBox_frame.add(self.RamachandranOutliersBox) - - RamachandranFavoredLabel_frame=gtk.Frame() - self.RamachandranFavoredLabel = gtk.Label('Rama Favored') - RamachandranFavoredLabel_frame.add(self.RamachandranFavoredLabel) - self.RamachandranFavoredValue = gtk.Label(self.QualityIndicators['RamachandranFavoredColor']) - RamachandranFavoredBox_frame=gtk.Frame() - self.RamachandranFavoredBox = gtk.EventBox() - self.RamachandranFavoredBox.add(self.RamachandranFavoredValue) - RamachandranFavoredBox_frame.add(self.RamachandranFavoredBox) - - rmsdBondsLabel_frame=gtk.Frame() - self.rmsdBondsLabel = gtk.Label('rmsd(Bonds)') - rmsdBondsLabel_frame.add(self.rmsdBondsLabel) - self.rmsdBondsValue = gtk.Label(self.QualityIndicators['rmsdBonds']) - rmsdBondsBox_frame=gtk.Frame() - self.rmsdBondsBox = gtk.EventBox() - self.rmsdBondsBox.add(self.rmsdBondsValue) - rmsdBondsBox_frame.add(self.rmsdBondsBox) - - rmsdAnglesLabel_frame=gtk.Frame() - self.rmsdAnglesLabel = gtk.Label('rmsd(Angles)') - rmsdAnglesLabel_frame.add(self.rmsdAnglesLabel) - self.rmsdAnglesValue = gtk.Label(self.QualityIndicators['rmsdAngles']) - rmsdAnglesBox_frame=gtk.Frame() - self.rmsdAnglesBox = gtk.EventBox() - self.rmsdAnglesBox.add(self.rmsdAnglesValue) - rmsdAnglesBox_frame.add(self.rmsdAnglesBox) - - MatrixWeightLabel_frame=gtk.Frame() - self.MatrixWeightLabel = gtk.Label('Matrix Weight') - MatrixWeightLabel_frame.add(self.MatrixWeightLabel) - self.MatrixWeightValue = gtk.Label(self.QualityIndicators['MatrixWeight']) - MatrixWeightBox_frame=gtk.Frame() - self.MatrixWeightBox = gtk.EventBox() - self.MatrixWeightBox.add(self.MatrixWeightValue) - MatrixWeightBox_frame.add(self.MatrixWeightBox) - - outer_frame = gtk.Frame() - hbox = gtk.HBox() - - frame = gtk.Frame() - self.table_left = gtk.Table(8, 2, False) - self.table_left.attach(RRfreeLabel_frame, 0, 1, 0, 1) - self.table_left.attach(ResolutionLabel_frame, 0, 1, 1, 2) - self.table_left.attach(MolprobityScoreLabel_frame, 0, 1, 2, 3) - self.table_left.attach(RamachandranOutliersLabel_frame, 0, 1, 3, 4) - self.table_left.attach(RamachandranFavoredLabel_frame, 0, 1, 4, 5) - self.table_left.attach(rmsdBondsLabel_frame, 0, 1, 5, 6) - self.table_left.attach(rmsdAnglesLabel_frame, 0, 1, 6, 7) - self.table_left.attach(MatrixWeightLabel_frame, 0, 1, 7, 8) - self.table_left.attach(RRfreeBox_frame, 1, 2, 0, 1) - self.table_left.attach(ResolutionBox_frame, 1, 2, 1, 2) - self.table_left.attach(MolprobityScoreBox_frame, 1, 2, 2, 3) - self.table_left.attach(RamachandranOutliersBox_frame, 1, 2, 3, 4) - self.table_left.attach(RamachandranFavoredBox_frame, 1, 2, 4, 5) - self.table_left.attach(rmsdBondsBox_frame, 1, 2, 5, 6) - self.table_left.attach(rmsdAnglesBox_frame, 1, 2, 6, 7) - self.table_left.attach(MatrixWeightBox_frame, 1, 2, 7, 8) - frame.add(self.table_left) - hbox.add(frame) - - outer_frame.add(hbox) - self.vbox.add(outer_frame) - - button = gtk.Button(label="Show MolProbity to-do list") - button.connect("clicked",self.show_molprobity_to_do) - self.vbox.add(button) - self.vbox.pack_start(frame) - - # SPACER - self.vbox.add(gtk.Label(' ')) - - # --- refinement & options --- - self.hbox_for_refinement=gtk.HBox() - self.REFINEbutton = gtk.Button(label="Refine") - self.RefinementParamsButton = gtk.Button(label="refinement parameters") - self.REFINEbutton.connect("clicked",self.REFINE) - self.hbox_for_refinement.add(self.REFINEbutton) - self.RefinementParamsButton.connect("clicked",self.RefinementParams) - self.hbox_for_refinement.add(self.RefinementParamsButton) - self.vbox.add(self.hbox_for_refinement) - - # --- CANCEL button --- - self.CANCELbutton = gtk.Button(label="CANCEL") - self.CANCELbutton.connect("clicked", self.CANCEL) - self.vbox.add(self.CANCELbutton) - - self.window.add(self.vbox) - self.window.show_all() - - def CANCEL(self,widget): - self.window.destroy() - - - def RefreshData(self): - - # initialize Refinement library - self.Refine=XChemRefine.Refine(self.reference_directory,self.refinementDir,'dummy_compound_ID','dummy_database') - self.Serial=self.Refine.GetSerial() - print '====> Serial',self.Serial - - ######################################################################################### - # history - # if the structure was previously refined, try to read the parameters - self.hbox_for_info_graphics.remove(self.canvas) - if self.Serial > 1: - self.RefmacParams=self.Refine.ParamsFromPreviousCycle(self.Serial-1) - refinement_cycle,Rfree,Rcryst=self.Refine.GetRefinementHistory() - self.canvas = FigureCanvas(self.update_plot(refinement_cycle,Rfree,Rcryst)) - else: - self.canvas = FigureCanvas(self.update_plot([0],[0],[0])) # a gtk.DrawingArea - self.canvas.set_size_request(190, 190) - self.hbox_for_info_graphics.add(self.canvas) - self.canvas.show() - - ######################################################################################### - # update Quality Indicator table - print self.QualityIndicators - try: - self.RRfreeValue.set_label( str(round(float(self.QualityIndicators['Rcryst']),3)) +' / '+str(round(float(self.QualityIndicators['Rfree']),3))) - except ValueError: - self.RRfreeValue.set_label('-') - - try: - self.RRfreeBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RfreeTL'])) - except ValueError: - pass - self.ResolutionValue.set_label(self.QualityIndicators['ResolutionHigh']) - try: - self.ResolutionBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['ResolutionColor'])) - except ValueError: - pass - self.MolprobityScoreValue.set_label(self.QualityIndicators['MolprobityScore']) - try: - self.MolprobityScoreBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['MolprobityScoreColor'])) - except ValueError: - pass - self.RamachandranOutliersValue.set_label(self.QualityIndicators['RamachandranOutliers']) - try: - self.RamachandranOutliersBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RamachandranOutliersColor'])) - except ValueError: - pass - self.RamachandranFavoredValue.set_label(self.QualityIndicators['RamachandranFavored']) - try: - self.RamachandranFavoredBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['RamachandranFavoredColor'])) - except ValueError: - pass - self.rmsdBondsValue.set_label(self.QualityIndicators['rmsdBonds']) - try: - self.rmsdBondsBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['rmsdBondsTL'])) - except ValueError: - pass - self.rmsdAnglesValue.set_label(self.QualityIndicators['rmsdAngles']) - try: - self.rmsdAnglesBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.QualityIndicators['rmsdAnglesTL'])) - except ValueError: - pass - self.MatrixWeightValue.set_label(self.QualityIndicators['MatrixWeight']) - - - def REFINE(self,widget): - - if self.job_running: - coot.info_dialog('*** refinement in progress ***') - return None - - ####################################################### - # create folder for new refinement cycle and check if free.mtz exists - if not os.path.isdir(os.path.join(self.reference_directory,self.refinementDir)): - os.mkdir(os.path.join(self.reference_directory,self.refinementDir)) - if not os.path.isdir(os.path.join(self.reference_directory,self.refinementDir,'Refine_'+str(self.Serial))): - os.mkdir(os.path.join(self.reference_directory,self.refinementDir,'Refine_'+str(self.Serial))) - if not os.path.isfile(os.path.join(self.reference_directory,self.refinementDir,self.refinementDir+'.free.mtz')): - os.chdir(os.path.join(self.reference_directory,self.refinementDir)) - os.symlink(self.mtzFree,self.refinementDir+'.free.mtz') - - ####################################################### - # write PDB file - # now take protein pdb file and write it to newly create Refine_ folder - # note: the user has to make sure that the ligand file was merged into main file - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item) in self.pdbFile: - coot.write_pdb_file(item,os.path.join(self.reference_directory,self.refinementDir,'Refine_'+str(self.Serial),'in.pdb')) - break - - self.Refine.RunRefmac(self.Serial,self.RefmacParams,self.external_software,self.xce_logfile,None) -# self.spinnerBox.add(self.refinementRunning) -# self.refinementRunning.start() - self.status_label.set_text('Refinement running...') - - time.sleep(1) # waiting 1s to make sure that REFINEMENT_IN_PROGRESS is written - snooze = 0 - while os.path.exists(os.path.join(self.reference_directory,self.refinementDir,'REFINEMENT_IN_PROGRESS')): - time.sleep(10) - print '==> XCE: waiting for refinement to finish; elapsed time = ' + str(snooze) + 's' - snooze += 10 - self.update_pdb_mtz_files('') - - - # launch refinement -# time.sleep(1) # waiting 1s to make sure that REFINEMENT_IN_PROGRESS is written -# self.source_id = gobject.timeout_add(100, self.wait_for_refined_pdb) - -# def wait_for_refined_pdb(self): -# self.spinnerBox.add(self.refinementRunning) -# self.refinementRunning.show() -# self.refinementRunning.start() -# if not os.path.isfile(os.path.join(self.reference_directory,self.refinementDir,'REFINEMENT_IN_PROGRESS')): -# self.job_running=False -# self.end_thread('update_pdb_mtz') -# return True - -# def end_thread(self,action): -# self.refinementRunning.stop() -# self.spinnerBox.remove(self.refinementRunning) -# self.status_label.set_text('idle') -# gobject.source_remove(self.source_id) -# if action=='update_pdb_mtz': -# self.update_pdb_mtz_files('') - - - - def RefinementParams(self,widget): - print '\n==> XCE: changing refinement parameters' - self.RefmacParams=self.Refine.RefinementParams(self.RefmacParams) - - def set_selection_mode(self,widget): - self.selection_mode=widget.get_active_text() - - - def load_pdb_file(self,widget): - pdbRoot=self.cb_select_pdb.get_active_text() - if self.pdbFile != '': - self.Logfile.error('sorry, you need to close the current instance of COOT and start again') - return None - - self.refinementDir=pdbRoot.replace('.pdb','') - self.update_pdb_mtz_files(pdbRoot) - - def update_pdb_mtz_files(self,pdbRoot): - # first remove all pdb and mtz files from memory - self.Logfile.insert('removing all PDB and MTZ files from memory') - if len(coot_utils_XChem.molecule_number_list()) > 0: - for item in coot_utils_XChem.molecule_number_list(): - if coot.molecule_name(item).endswith('.pdb') or '.mtz' in coot.molecule_name(item): - self.Logfile.insert('removing %s' %coot.molecule_name(item)) - coot.close_molecule(item) - - coot.set_nomenclature_errors_on_read("ignore") - # first we check if there is a refinement folder and the respective refine.pdb - # from previous refinement cycles - Root=self.cb_select_pdb.get_active_text() - print 'ROOT',Root - print 'REFI_DIR',os.path.join(self.reference_directory,self.refinementDir,'refine.pdb') - if os.path.isfile(os.path.join(self.reference_directory,self.refinementDir,'refine.pdb')): - os.chdir(self.reference_directory) - print 'CURRENT DIR',os.getcwd() - os.system('/bin/rm %s 2> /dev/null' %Root) - os.symlink(os.path.realpath(os.path.join(self.refinementDir,'refine.pdb')),'%s' %Root) - self.pdbFile=os.path.join(self.reference_directory,self.refinementDir,'refine.pdb') - elif os.path.isfile(os.path.join(self.reference_directory,Root)): - self.pdbFile=os.path.join(self.reference_directory,Root) - else: - self.Logfile.error('cannot find PDB file') - - if self.pdbFile != '': -# os.chdir(os.path.join(self.reference_directory,self.refinementDir)) - coot.set_colour_map_rotation_on_read_pdb(0) - imol=coot.handle_read_draw_molecule_with_recentre(self.pdbFile,0) - self.QualityIndicators=XChemUtils.parse().PDBheader(os.path.join(self.pdbFile)) - self.QualityIndicators.update(XChemUtils.logtools(os.path.join(self.reference_directory,self.refinementDir,'refine_molprobity.log')).phenix_molprobity()) - self.QualityIndicators.update(XChemUtils.logtools(os.path.join(self.reference_directory,self.refinementDir,'Refine_'+str(self.Serial),'refmac.log')).refmac_log()) - self.mol_dict['protein']=imol - - - if self.mtzFree=='': - print 'FREE',os.path.join(self.reference_directory,pdbRoot.replace('.pdb','')+'.free.mtz') - if os.path.isfile(os.path.join(self.reference_directory,pdbRoot.replace('.pdb','')+'.free.mtz')): - self.mtzFree=os.path.join(self.reference_directory,pdbRoot.replace('.pdb','')+'.free.mtz') - self.mtzFree_label.set_text(pdbRoot.replace('.pdb','')+'.free.mtz') - self.REFINEbutton.set_sensitive(True) - else: - self.mtzFree_label.set_text('missing file') - self.Logfile.error('cannot find file with F,SIGF and FreeR_flag; cannot start refinement') - self.REFINEbutton.set_sensitive(False) - - self.mtzRefine='' - if os.path.isfile(os.path.join(self.reference_directory,self.refinementDir,'refine.mtz')): - self.mtzRefine=os.path.join(self.reference_directory,self.refinementDir,'refine.mtz') - mtzRefineReal = os.path.realpath(os.path.join(self.reference_directory,self.refinementDir,'refine.mtz')) - mtzRefineCurrent = mtzRefineReal.replace(os.path.join(self.reference_directory,self.refinementDir+'/'),'') - self.mtzRefine_label.set_text(mtzRefineCurrent) - coot.set_default_initial_contour_level_for_map(1) - if os.path.isfile(os.path.join(self.reference_directory,self.refinementDir,self.mtz_style)): - coot.auto_read_make_and_draw_maps(os.path.join(self.reference_directory,self.refinementDir,self.mtz_style)) - else: - self.mtzRefine_label.set_text('missing file') - self.Logfile.warning('cannot find file with F,SIGF and FreeR_flag; cannot start refinement') - - groundStateMap = os.path.join(self.reference_directory,Root+'-mean-map.native.ccp4').replace('.pdb','') - print '===>',groundStateMap - if os.path.isfile(groundStateMap): - imol=coot.handle_read_ccp4_map(groundStateMap,0) - coot.set_contour_level_in_sigma(imol,1) - coot.set_last_map_colour(0.6,0.6,0) - else: - print '==> XCE: ERROR - cannot find ground state mean map!' - - self.RefreshData() - -# def load_ground_state_map(self,widget): -# self.spinnerBox.add(self.refinementRunning) -# self.refinementRunning.start() -# self.status_label.set_text('loading ground state maps by reso...') -# self.source_id = gobject.timeout_add(100, self.load_ground_state_map_thread) - - -# def load_ground_state_map_thread(self): -# self.spinnerBox.add(self.refinementRunning) -# self.refinementRunning.show() -# self.refinementRunning.start() -# -# # first remove all ground state maps files -# if len(coot_utils_XChem.molecule_number_list()) > 0: -# for item in coot_utils_XChem.molecule_number_list(): -# if 'ground-state-mean-map' in coot.molecule_name(item): -# coot.close_molecule(item) -# -# # first remove all entries for self.cb_select_mean_map_by_resolution -# # clear CB first, 100 is sort of arbitrary since it's unlikely there will ever be 100 maps -# for n in range(-1,100): -# self.cb_select_mean_map_by_resolution.remove_text(0) -# -# self.status_label.set_text('loading ground state maps') -# self.get_highest_reso_ground_state_map() -# blueStart=0.02 -# for map in self.ground_state_map_List: -# self.cb_select_mean_map_by_resolution.append_text(map[0]) -# imol=coot.handle_read_ccp4_map((map[1]),0) -# coot.set_contour_level_in_sigma(imol,1) -# coot.set_last_map_colour(0.74,0.44,blueStart) -# blueStart+=0.05 -# # show only highest resolution map to start with -# self.show_highres_ground_state_map() -# self.cb_select_mean_map_by_resolution.set_active(0) -# self.end_thread('') - -# def show_highres_ground_state_map(self): -# if len(self.ground_state_map_List) >= 1: -# for imol in coot_utils_XChem.molecule_number_list(): -# if coot.molecule_name(imol) in self.ground_state_map_List[0][1]: -# coot.set_map_displayed(imol,1) -# elif 'ground-state-mean-map' in coot.molecule_name(imol): -# coot.set_map_displayed(imol,0) - -# def show_all_ground_state_map(self): -# if len(self.ground_state_map_List) >= 1: -# for imol in coot_utils_XChem.molecule_number_list(): -# if 'ground-state-mean-map' in coot.molecule_name(imol): -# coot.set_map_displayed(imol,1) - -# def show_selected_mean_map(self,widget): -# reso=str(self.cb_select_mean_map_by_resolution.get_active_text()) -# mapToshow='' -# for maps in self.ground_state_map_List: -# if maps[0]==reso: -# mapToshow=maps[1] -# for imol in coot_utils_XChem.molecule_number_list(): -# if coot.molecule_name(imol) in mapToshow: -# coot.set_map_displayed(imol,1) -# elif 'ground-state-mean-map' in coot.molecule_name(imol): -# coot.set_map_displayed(imol,0) - - def show_molprobity_to_do(self,widget): - if os.path.isfile(os.path.join(self.reference_directory,self.refinementDir,'Refine_'+str(self.Serial-1),'molprobity_coot.py')): - coot.run_script(os.path.join(self.reference_directory,self.refinementDir,'Refine_'+str(self.Serial-1),'molprobity_coot.py')) - else: - print '==> XCE: cannot find '+os.path.join(self.reference_directory,self.xtalID,'Refine_'+str(self.Serial-1),'molprobity_coot.py') - - def update_plot(self,refinement_cycle,Rfree,Rcryst): - fig = Figure(figsize=(2, 2), dpi=50) - Plot = fig.add_subplot(111) - Plot.set_ylim([0,max(Rcryst+Rfree)]) - Plot.set_xlabel('Refinement Cycle',fontsize=12) - Plot.plot(refinement_cycle,Rfree,label='Rfree',linewidth=2) - Plot.plot(refinement_cycle,Rcryst,label='Rcryst',linewidth=2) - Plot.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, - ncol=2, mode="expand", borderaxespad=0.,fontsize=12) - return fig - - def get_ground_state_maps_by_resolution(self): - found=False - mapList=[] - for logFile in glob.glob(os.path.join(self.reference_directory,str(self.cb_select_mean_map.get_active_text()),'logs','*.log')): - for n,line in enumerate(open(logFile)): - if line.startswith('Statistical Electron Density Characterisation') and len(line.split()) == 6: -# try: -# resolution=float(line.split()[5]) - resolution=line.split()[5] - print resolution - found=True - foundLine=n -# except ValueError: -# print 'error' -# break - if found and n==foundLine+3: - xtal=line.split(',')[0].replace(' ','').replace('\t','') - meanmap=os.path.join(self.reference_directory,self.cb_select_mean_map.get_active_text(),'processed_datasets',xtal,xtal+'-ground-state-mean-map.native.ccp4') - mapList.append([resolution,meanmap]) - found=False - return mapList - - def get_highest_reso_ground_state_map(self): - mapList = self.get_ground_state_maps_by_resolution() - print mapList - self.ground_state_map_List=[] - self.ground_state_map_List.append(min(mapList, key=lambda x: x[0])) - return self.ground_state_map_List - - -if __name__=='__main__': - GUI().StartGUI() diff --git a/lib/XChemDB.py b/lib/XChemDB.py deleted file mode 100755 index 1a1b3e08..00000000 --- a/lib/XChemDB.py +++ /dev/null @@ -1,1949 +0,0 @@ -# last edited: 21/07/2017, 15:00 - -import sqlite3 -import os,sys,glob -import csv -from datetime import datetime -import getpass - -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -#from XChemUtils import parse -import XChemLog - - -class data_source: - - def __init__(self,data_source_file): - - self.data_source_file=data_source_file - - # [column_name in DB, column_name shown in XCE, SQLite column type (Integer,Text,PKEY...)] - self.column_list=[ - # SQLite column name XCE column name SQLite type display in overview tab - # from Lab36 - ['ID', 'ID', 'INTEGER PRIMARY KEY', 0], - ['LabVisit', 'LabVisit', 'TEXT', 1], - ['LibraryPlate', 'LibraryPlate', 'TEXT', 0], - ['SourceWell', 'SourceWell', 'TEXT', 0], - ['LibraryName', 'LibraryName', 'TEXT', 1], - ['CompoundSMILES', 'Smiles', 'TEXT', 1], - ['CompoundSMILESproduct', 'Smiles - Product', 'TEXT', 1], - ['CompoundCode', 'Compound ID', 'TEXT', 1], - ['CompoundStereo', 'Compound Stereo', 'TEXT', 1], - ['CompoundStereoSMILES', 'Stereo SMILES', 'TEXT', 1], - ['CompoundStereoCIFprogram', 'Stereo CIF program', 'TEXT', 1], - ['CompoundStereoCIFs', 'Compound Stereo IDs', 'TEXT', 1], - ['CompoundAutofitCC', 'autofit CC', 'TEXT', 1], - ['CompoundAutofitprogram', 'autofit program', 'TEXT', 1], - ['CrystalPlate', 'CrystalPlate', 'TEXT', 1], - ['CrystalWell', 'CrystalWell', 'TEXT', 1], - ['EchoX', 'EchoX', 'TEXT', 0], - ['EchoY', 'EchoY', 'TEXT', 0], - ['DropVolume', 'DropVolume', 'TEXT', 0], - ['ProteinName', 'ProteinName', 'TEXT', 1], - ['BatchNumber', 'BatchNumber', 'TEXT', 0], - ['CompoundStockConcentration', 'CompoundStockConcentration', 'TEXT', 0], - ['CompoundConcentration', 'CompoundConcentration', 'TEXT', 1], - ['SolventFraction', 'SolventFraction', 'TEXT', 1], - ['SoakTransferVol', 'SoakTransferVol', 'TEXT', 0], - ['SoakStatus', 'SoakStatus', 'TEXT', 0], - ['SoakTimestamp', 'SoakTimestamp', 'TEXT', 0], - ['CryoStockFraction', 'CryoStockFraction', 'TEXT', 0], - ['CryoFraction', 'CryoFraction', 'TEXT', 0], - ['CryoWell', 'CryoWell', 'TEXT', 0], - ['CryoTransferVolume', 'CryoTransferVolume', 'TEXT', 0], - ['CryoStatus', 'CryoStatus', 'TEXT', 0], - ['CryoTimestamp', 'CryoTimestamp', 'TEXT', 0], - ['SoakingTime', 'SoakingTime', 'TEXT', 1], - ['HarvestStatus', 'HarvestStatus', 'TEXT', 0], - ['CrystalName', 'Sample ID', 'TEXT', 0], - ['Puck', 'Puck', 'TEXT', 1], - ['PuckPosition', 'PuckPosition', 'TEXT', 1], - ['PinBarcode', 'SoakDB\nBarcode', 'TEXT', 1], - ['MountingResult', 'MountingResult', 'TEXT', 0], - ['MountingArrivalTime', 'MountingArrivalTime', 'TEXT', 0], - ['MountedTimestamp', 'MountedTimestamp', 'TEXT', 0], - ['MountingTime', 'MountingTime', 'TEXT', 0], - ['ispybStatus', 'ispybStatus', 'TEXT', 0], - ['DataCollectionVisit', 'Visit', 'TEXT', 1], - - # from XChemExplorer - - ['ProjectDirectory', 'ProjectDirectory', 'TEXT', 0], - - ['CrystalTag', 'Tag', 'TEXT', 0], - ['CrystalFormName', 'Crystal Form\nName', 'TEXT', 0], - ['CrystalFormSpaceGroup', 'Space\nGroup', 'TEXT', 0], - ['CrystalFormPointGroup', 'Point\nGroup', 'TEXT', 0], - ['CrystalFormA', 'a', 'TEXT', 0], - ['CrystalFormB', 'b', 'TEXT', 0], - ['CrystalFormC', 'c', 'TEXT', 0], - ['CrystalFormAlpha', 'alpha', 'TEXT', 0], - ['CrystalFormBeta', 'beta', 'TEXT', 0], - ['CrystalFormGamma', 'gamma', 'TEXT', 0], - ['CrystalFormVolume', 'Crystal Form\nVolume', 'TEXT', 0], - - ['DataCollectionBeamline', 'Beamline', 'TEXT', 0], - ['DataCollectionDate', 'Data Collection\nDate', 'TEXT', 1], - ['DataCollectionOutcome', 'DataCollection\nOutcome', 'TEXT', 1], - ['DataCollectionRun', 'Run', 'TEXT', 0], - ['DataCollectionComment', 'DataCollection\nComment', 'TEXT', 0], - ['DataCollectionWavelength', 'Wavelength', 'TEXT', 0], - ['DataCollectionPinBarcode', 'GDA\nBarcode', 'TEXT', 1], - - ['DataCollectionCrystalImage1', 'img1', 'TEXT', 1], - ['DataCollectionCrystalImage2', 'img2', 'TEXT', 1], - ['DataCollectionCrystalImage3', 'img3', 'TEXT', 1], - ['DataCollectionCrystalImage4', 'img4', 'TEXT', 1], - - ['DataProcessingPathToImageFiles', 'Path to diffraction\nimage files', 'TEXT', 1], - ['DataProcessingProgram', 'Program', 'TEXT', 1], - ['DataProcessingSpaceGroup', 'DataProcessing\nSpaceGroup', 'TEXT', 1], - ['DataProcessingUnitCell', 'DataProcessing\nUnitCell', 'TEXT', 0], - ['DataProcessingAutoAssigned', 'auto-assigned', 'TEXT', 0], - - ['DataProcessingA', 'DataProcessing\nA', 'TEXT', 0], - ['DataProcessingB', 'DataProcessing\nB', 'TEXT', 0], - ['DataProcessingC', 'DataProcessing\nC', 'TEXT', 0], - ['DataProcessingAlpha', 'DataProcessing\nAlpha', 'TEXT', 0], - ['DataProcessingBeta', 'DataProcessing\nBeta', 'TEXT', 0], - ['DataProcessingGamma', 'DataProcessing\nGamma', 'TEXT', 0], - - # True or False depending on whether user changed automatic selection -# ['DataProcessingUserSelected', 'DataProcessingUserSelected', 'TEXT', 0], - - ['DataProcessingResolutionOverall', 'Resolution\nOverall', 'TEXT', 0], - ['DataProcessingResolutionLow', 'Resolution\nLow', 'TEXT', 0], - ['DataProcessingResolutionLowInnerShell', 'Resolution\nLow (Inner Shell)', 'TEXT', 0], - ['DataProcessingResolutionHigh', 'Resolution\nHigh', 'TEXT', 1], - ['DataProcessingResolutionHigh15sigma', 'Resolution\n[Mn = 1.5]', 'TEXT', 1], - ['DataProcessingResolutionHigh20sigma', 'Resolution\n[Mn = 2.0]', 'TEXT', 1], - ['DataProcessingResolutionHighOuterShell', 'Resolution\nHigh (Outer Shell)', 'TEXT', 0], - ['DataProcessingRmergeOverall', 'Rmerge\nOverall', 'TEXT', 1], - ['DataProcessingRmergeLow', 'Rmerge\nLow', 'TEXT', 1], - ['DataProcessingRmergeHigh', 'Rmerge\nHigh', 'TEXT', 1], - ['DataProcessingIsigOverall', 'Mn\nOverall', 'TEXT', 1], - ['DataProcessingIsigLow', 'Mn\nLow', 'TEXT', 1], - ['DataProcessingIsigHigh', 'Mn\nHigh', 'TEXT', 1], - ['DataProcessingCompletenessOverall', 'Completeness\nOverall', 'TEXT', 1], - ['DataProcessingCompletenessLow', 'Completeness\nLow', 'TEXT', 1], - ['DataProcessingCompletenessHigh', 'Completeness\nHigh', 'TEXT', 1], - ['DataProcessingMultiplicityOverall', 'Multiplicity\nOverall', 'TEXT', 1], - ['DataProcessingMultiplicityLow', 'Multiplicity\nLow', 'TEXT', 1], - ['DataProcessingMultiplicityHigh', 'Multiplicity\nHigh', 'TEXT', 1], - ['DataProcessingCChalfOverall', 'CC(1/2)\nOverall', 'TEXT', 1], - ['DataProcessingCChalfLow', 'CC(1/2)\nLow', 'TEXT', 1], - ['DataProcessingCChalfHigh', 'CC(1/2)\nHigh', 'TEXT', 1], - - # the data source is a bit exploding with entries like the ones below, - # but the many different filenames and folder structures of Diamond autoprocessing makes it necessary - ['DataProcessingPathToLogfile', 'DataProcessingPathToLogfile', 'TEXT', 1], - ['DataProcessingPathToMTZfile', 'DataProcessingPathToMTZfile', 'TEXT', 1], - ['DataProcessingLOGfileName', 'DataProcessingLOGfileName', 'TEXT', 0], - ['DataProcessingMTZfileName', 'DataProcessingMTZfileName', 'TEXT', 0], - ['DataProcessingDirectoryOriginal', 'DataProcessingDirectoryOriginal', 'TEXT', 0], - - ['DataProcessingUniqueReflectionsOverall', 'Unique Reflections\nOverall', 'TEXT', 1], - ['DataProcessingLattice', 'DataProcessing\nLattice', 'TEXT', 0], - ['DataProcessingPointGroup', 'DataProcessing\nPointGroup', 'TEXT', 0], - ['DataProcessingUnitCellVolume', 'DataProcessing\nUnit Cell Volume', 'TEXT', 0], - ['DataProcessingAlert', 'DataProcessing\nAlert', 'TEXT', 0], - ['DataProcessingScore', 'DataProcessing\nScore', 'TEXT', 1], - - ['DataProcessingStatus', 'DataProcessing\nStatus', 'TEXT', 1], - - ['DataProcessingRcryst', 'DataProcessing\nRcryst', 'TEXT', 0], - ['DataProcessingRfree', 'DataProcessing\nRfree', 'TEXT', 0], - ['DataProcessingPathToDimplePDBfile', 'DataProcessingPathToDimplePDBfile', 'TEXT', 0], - ['DataProcessingPathToDimpleMTZfile', 'DataProcessingPathToDimpleMTZfile', 'TEXT', 0], - ['DataProcessingDimpleSuccessful', 'DataProcessingDimpleSuccessful', 'TEXT', 0], - - ['DimpleResolutionHigh', 'Dimple\nResolution High', 'TEXT', 1], - ['DimpleRcryst', 'Dimple\nRcryst', 'TEXT', 1], - ['DimpleRfree', 'Dimple\nRfree', 'TEXT', 1], - ['DimplePathToPDB', 'Dimple\nPath to PDB file', 'TEXT', 1], - ['DimplePathToMTZ', 'Dimple\nPath to MTZ file', 'TEXT', 1], - ['DimpleReferencePDB', 'Dimple\nReference PDB', 'TEXT', 1], - ['DimpleStatus', 'Dimple\nStatus', 'TEXT', 1], - - ['DimplePANDDAwasRun', 'PanDDA\nlaunched?', 'TEXT', 1], - ['DimplePANDDAhit', 'PanDDA\nhit?', 'TEXT', 1], - ['DimplePANDDAreject', 'PanDDA\nreject?', 'TEXT', 1], - ['DimplePANDDApath', 'PanDDA\npath?', 'TEXT', 1], - ['PANDDAStatus', 'PanDDA\nStatus', 'TEXT', 1], - - ['DatePanDDAModelCreated', 'DatePanDDAModelCreated', 'TEXT', 0], - - ['RefinementResolution', 'Refinement\nResolution', 'TEXT', 1], - ['RefinementResolutionTL', 'RefinementResolutionTL', 'TEXT', 0], - ['RefinementRcryst', 'Refinement\nRcryst', 'TEXT', 1], - ['RefinementRcrystTraficLight', 'RefinementRcrystTraficLight', 'TEXT', 0], - ['RefinementRfree', 'Refinement\nRfree', 'TEXT', 1], - ['RefinementRfreeTraficLight', 'RefinementRfreeTraficLight', 'TEXT', 0], - ['RefinementSpaceGroup', 'Refinement\nSpace Group', 'TEXT', 1], - ['RefinementLigandCC', 'RefinementLigandCC', 'TEXT', 0], - ['RefinementRmsdBonds', 'RefinementRmsdBonds', 'TEXT', 1], - ['RefinementRmsdBondsTL', 'RefinementRmsdBondsTL', 'TEXT', 0], - ['RefinementRmsdAngles', 'RefinementRmsdAngles', 'TEXT', 1], - ['RefinementRmsdAnglesTL', 'RefinementRmsdAnglesTL', 'TEXT', 0], - ['RefinementOutcome', 'Refinement\nOutcome', 'TEXT', 1], - ['RefinementMTZfree', 'RefinementMTZfree', 'TEXT', 1], - ['RefinementCIF', 'RefinementCIF', 'TEXT', 1], - ['RefinementCIFStatus', 'Compound\nStatus', 'TEXT', 1], - ['RefinementCIFprogram', 'RefinementCIFprogram', 'TEXT', 1], - ['RefinementPDB_latest', 'RefinementPDB_latest', 'TEXT', 1], - ['RefinementMTZ_latest', 'RefinementMTZ_latest', 'TEXT', 1], - ['RefinementMatrixWeight', 'RefinementMatrixWeight', 'TEXT', 0], - ['RefinementComment', 'RefinementComment', 'TEXT', 0], - ['RefinementPathToRefinementFolder', 'RefinementPathToRefinementFolder', 'TEXT', 0], - ['RefinementLigandConfidence', 'Ligand\nConfidence', 'TEXT', 0], - ['RefinementLigandBoundConformation', 'RefinementLigandBoundConformation', 'TEXT', 0], - ['RefinementBoundConformation', 'RefinementBoundConformation', 'TEXT', 0], - ['RefinementMolProbityScore', 'MolProbity Score', 'TEXT', 1], - ['RefinementMolProbityScoreTL', 'RefinementMolProbityScoreTL', 'TEXT', 0], - ['RefinementRamachandranOutliers', 'Ramachandran\nOutliers', 'TEXT', 1], - ['RefinementRamachandranOutliersTL', 'RefinementRamachandranOutliersTL', 'TEXT', 0], - ['RefinementRamachandranFavored', 'Ramachandran\nFavored', 'TEXT', 1], - ['RefinementRamachandranFavoredTL', 'RefinementRamachandranFavoredTL', 'TEXT', 0], - ['RefinementProgram', 'RefinementProgram', 'TEXT', 1], - ['RefinementStatus', 'Refinement\nStatus', 'TEXT', 1], - - ['Deposition_PDB_ID', 'Deposition_PDB_ID', 'TEXT', 1], - ['Deposition_PDB_file', 'Deposition_PDB_file', 'TEXT', 0], - ['Deposition_Date', 'Deposition_Date', 'TEXT', 1], - ['Deposition_mmCIF_model_file', 'Deposition_mmCIF_model_file', 'TEXT', 0], - ['Deposition_mmCIF_SF_file', 'Deposition_mmCIF_SF_file', 'TEXT', 0], - - ['Label', 'Label', 'TEXT', 0], - ['table_one', 'table_one', 'TEXT', 0], - - ['AssayIC50', 'AssayIC50', 'TEXT', 0], - ['LastUpdated', 'LastUpdated', 'TEXT', 0], - ['LastUpdated_by', 'LastUpdated_by', 'TEXT', 0] - ] - - self.pandda_table_columns = [ - ['ID', 'ID', 'INTEGER PRIMARY KEY'], - ['CrystalName', 'Sample ID', 'TEXT'], - ['PANDDApath', 'PANDDApath', 'TEXT'], - ['PANDDA_site_index', 'PANDDA_site_index', 'TEXT'], - ['PANDDA_site_name', 'PANDDA_site_name', 'TEXT'], - ['PANDDA_site_comment', 'PANDDA_site_comment', 'TEXT'], - ['PANDDA_site_event_index', 'PANDDA_site_event_index', 'TEXT'], - ['PANDDA_site_event_comment', 'PANDDA_site_event_comment', 'TEXT'], - ['PANDDA_site_confidence', 'PANDDA_site_confidence', 'TEXT'], - ['PANDDA_site_InspectConfidence', 'PANDDA_site_InspectConfidence', 'TEXT'], - ['PANDDA_site_ligand_placed', 'PANDDA_site_ligand_placed', 'TEXT'], - ['PANDDA_site_viewed', 'PANDDA_site_viewed', 'TEXT'], - ['PANDDA_site_interesting', 'PANDDA_site_interesting', 'TEXT'], - ['PANDDA_site_z_peak', 'PANDDA_site_z_peak', 'TEXT'], - ['PANDDA_site_x', 'PANDDA_site_x', 'TEXT'], - ['PANDDA_site_y', 'PANDDA_site_y', 'TEXT'], - ['PANDDA_site_z', 'PANDDA_site_z', 'TEXT'], - ['PANDDA_site_ligand_id', 'PANDDA_site_ligand_id', 'TEXT'], - - ['PANDDA_site_ligand_resname', 'PANDDA_site_ligand_resname', 'TEXT'], - ['PANDDA_site_ligand_chain', 'PANDDA_site_ligand_chain', 'TEXT'], - ['PANDDA_site_ligand_sequence_number', 'PANDDA_site_ligand_sequence_number', 'TEXT'], - ['PANDDA_site_ligand_altLoc', 'PANDDA_site_ligand_altLoc', 'TEXT'], - - ['PANDDA_site_event_map', 'PANDDA_site_event_map', 'TEXT'], - ['PANDDA_site_event_map_mtz', 'PANDDA_site_event_map_mtz', 'TEXT'], - ['PANDDA_site_initial_model', 'PANDDA_site_initial_model', 'TEXT'], - ['PANDDA_site_initial_mtz', 'PANDDA_site_initial_mtz', 'TEXT'], - ['PANDDA_site_spider_plot', 'PANDDA_site_spider_plot', 'TEXT'], - ['PANDDA_site_occupancy', 'PANDDA_site_occupancy', 'TEXT'], - ['PANDDA_site_B_average', 'PANDDA_site_B_average', 'TEXT'], - ['PANDDA_site_B_ratio_residue_surroundings', 'PANDDA_site_B_ratio_residue_surroundings', 'TEXT'], - ['PANDDA_site_RSCC', 'PANDDA_site_RSCC', 'TEXT'], - ['PANDDA_site_RSR', 'PANDDA_site_RSR', 'TEXT'], - ['PANDDA_site_RSZD', 'PANDDA_site_RSZD', 'TEXT'], - ['PANDDA_site_rmsd', 'PANDDA_site_rmsd', 'TEXT'], - ['RefinementOutcome', 'RefinementOutcome', 'TEXT'], - ['ApoStructures', 'ApoStructures', 'TEXT'], - ['LastUpdated', 'LastUpdated', 'TEXT'], - ['LastUpdated_by', 'LastUpdated_by', 'TEXT'] - ] - - self.deposition_table_columns = [ - ['ID', 'ID', 'INTEGER PRIMARY KEY'], - - ['CrystalName', 'Sample ID', 'TEXT'], - ['StructureType', 'StructureType', 'TEXT'], # apo/model - - ['PDB_file', 'PDB_file', 'TEXT'], - ['MTZ_file', 'MTZ_file', 'TEXT'], - - ['mmCIF_model_file', 'mmCIF_model_file', 'TEXT'], - ['mmCIF_SF_file', 'mmCIF_SF_file', 'TEXT'], - ['label', 'label', 'TEXT'], # for index.txt - ['description', 'description', 'TEXT'], # for index.txt - - ['DimplePANDDApath', 'DimplePANDDApath', 'TEXT'], - - ['contact_author_PI_salutation', 'contact_author_PI_salutation', 'TEXT'], - ['contact_author_PI_first_name', 'contact_author_PI_first_name', 'TEXT'], - ['contact_author_PI_last_name', 'contact_author_PI_last_name', 'TEXT'], - ['contact_author_PI_middle_name', 'contact_author_PI_middle_name', 'TEXT'], - ['contact_author_PI_role', 'contact_author_PI_role', 'TEXT'], - ['contact_author_PI_organization_type', 'contact_author_PI_organization_type', 'TEXT'], - ['contact_author_PI_organization_name', 'contact_author_PI_organization_name', 'TEXT'], - ['contact_author_PI_email', 'contact_author_PI_email', 'TEXT'], - ['contact_author_PI_address', 'contact_author_PI_address', 'TEXT'], - ['contact_author_PI_city', 'contact_author_PI_city', 'TEXT'], - ['contact_author_PI_State_or_Province', 'contact_author_PI_State_or_Province', 'TEXT'], - ['contact_author_PI_Zip_Code', 'contact_author_PI_Zip_Code', 'TEXT'], - ['contact_author_PI_Country', 'contact_author_PI_Country', 'TEXT'], - ['contact_author_PI_fax_number', 'contact_author_PI_fax_number', 'TEXT'], - ['contact_author_PI_phone_number', 'contact_author_PI_phone_number', 'TEXT'], - - ['contact_author_salutation', 'contact_author_salutation', 'TEXT'], - ['contact_author_first_name', 'contact_author_first_name', 'TEXT'], - ['contact_author_last_name', 'contact_author_last_name', 'TEXT'], - ['contact_author_middle_name', 'contact_author_middle_name', 'TEXT'], - ['contact_author_role', 'contact_author_role', 'TEXT'], - ['contact_author_organization_type', 'contact_author_organization_type', 'TEXT'], - ['contact_author_organization_name', 'contact_author_organization_name', 'TEXT'], - ['contact_author_email', 'contact_author_email', 'TEXT'], - ['contact_author_address', 'contact_author_address', 'TEXT'], - ['contact_author_city', 'contact_author_city', 'TEXT'], - ['contact_author_State_or_Province', 'contact_author_State_or_Province', 'TEXT'], - ['contact_author_Zip_Code', 'contact_author_Zip_Code', 'TEXT'], - ['contact_author_Country', 'contact_author_Country', 'TEXT'], - ['contact_author_fax_number', 'contact_author_fax_number', 'TEXT'], - ['contact_author_phone_number', 'contact_author_phone_number', 'TEXT'], - - ['Release_status_for_coordinates', 'Release_status_for_coordinates', 'TEXT'], - ['Release_status_for_structure_factor', 'Release_status_for_structure_factor', 'TEXT'], - ['Release_status_for_sequence', 'Release_status_for_sequence', 'TEXT'], - - ['group_deposition_title', 'group_deposition_title', 'TEXT'], - ['group_description', 'group_description', 'TEXT'], - ['structure_title', 'structure_title', 'TEXT'], - ['structure_details', 'structure_details', 'TEXT'], - ['group_deposition_title_apo', 'group_deposition_title_apo', 'TEXT'], - ['structure_title_apo', 'structure_title_apo', 'TEXT'], - - ['structure_author_name', 'structure_author_name', 'TEXT'], - ['primary_citation_author_name', 'primary_citation_author_name', 'TEXT'], - - ['primary_citation_id', 'primary_citation_id', 'TEXT'], - ['primary_citation_journal_abbrev', 'primary_citation_journal_abbrev', 'TEXT'], - ['primary_citation_title', 'primary_citation_title', 'TEXT'], - ['primary_citation_year', 'primary_citation_year', 'TEXT'], - ['primary_citation_journal_volume', 'primary_citation_journal_volume', 'TEXT'], - ['primary_citation_page_first', 'primary_citation_page_first', 'TEXT'], - ['primary_citation_page_last', 'primary_citation_page_last', 'TEXT'], - - ['molecule_name', 'molecule_name', 'TEXT'], - ['Fragment_name', 'Fragment_name', 'TEXT'], - ['Specific_mutation', 'Specific_mutation', 'TEXT'], - ['Enzyme_Comission_number', 'Enzyme_Comission_number', 'TEXT'], - ['Source_organism_scientific_name', 'Source_organism_scientific_name', 'TEXT'], - ['Source_organism_gene', 'Source_organism_gene', 'TEXT'], - ['Source_organism_strain', 'Source_organism_strain', 'TEXT'], - ['Expression_system_scientific_name', 'Expression_system_scientific_name', 'TEXT'], - ['Expression_system_strain', 'Expression_system_strain', 'TEXT'], - ['Expression_system_vector_type', 'Expression_system_vector_type', 'TEXT'], - ['Expression_system_plasmid_name', 'Expression_system_plasmid_name', 'TEXT'], - ['Manipulated_source_details', 'Manipulated_source_details', 'TEXT'], - ['fragment_name_one_specific_mutation', 'fragment_name_one_specific_mutation', 'TEXT'], - ['molecule_chain_one', 'molecule_chain_one', 'TEXT'], - - ['molecule_name_two', 'molecule_name_two', 'TEXT'], - ['Fragment_name_two', 'Fragment_name_two', 'TEXT'], - ['Specific_mutation_two', 'Specific_mutation_two', 'TEXT'], - ['Enzyme_Comission_number_two', 'Enzyme_Comission_number_two', 'TEXT'], - ['Source_organism_scientific_name_two', 'Source_organism_scientific_name_two', 'TEXT'], - ['Source_organism_gene_two', 'Source_organism_gene_two', 'TEXT'], - ['Source_organism_strain_two', 'Source_organism_strain_two', 'TEXT'], - ['Expression_system_scientific_name_two', 'Expression_system_scientific_name_two', 'TEXT'], - ['Expression_system_strain_two', 'Expression_system_strain_two', 'TEXT'], - ['Expression_system_vector_type_two', 'Expression_system_vector_type_two', 'TEXT'], - ['Expression_system_plasmid_name_two', 'Expression_system_plasmid_name_two', 'TEXT'], - ['Manipulated_source_details_two', 'Manipulated_source_details_two', 'TEXT'], - ['fragment_name_two_specific_mutation', 'fragment_name_one_specific_mutation_two', 'TEXT'], - ['molecule_chain_two', 'molecule_chain_two', 'TEXT'], - - ['structure_keywords', 'structure_keywords', 'TEXT'], - ['biological_assembly_chain_number', 'biological_assembly_chain_number', 'TEXT'], - - - ['crystallization_id', 'crystallization_id', 'TEXT'], - ['crystallization_method', 'crystallization_method', 'TEXT'], - ['crystallization_pH', 'crystallization_pH', 'TEXT'], - ['crystallization_temperature', 'crystallization_temperature', 'TEXT'], - ['crystallization_details', 'crystallization_details', 'TEXT'], - - ['radiation_source', 'radiation_source', 'TEXT'], - ['radiation_source_type', 'radiation_source_type', 'TEXT'], - ['radiation_wavelengths', 'radiation_wavelengths', 'TEXT'], - ['radiation_detector', 'radiation_detector', 'TEXT'], - ['radiation_detector_type', 'radiation_detector_type', 'TEXT'], - ['data_collection_date', 'data_collection_date', 'TEXT'], - ['data_collection_temperature', 'data_collection_temperature', 'TEXT'], - ['data_collection_protocol', 'data_collection_protocol', 'TEXT'], - - ['SG_project_name', 'SG_project_name', 'TEXT'], - ['full_name_of_SG_center', 'full_name_of_SG_center', 'TEXT'], - - ['molecule_one_letter_sequence', 'molecule_one_letter_sequence', 'TEXT'], - ['molecule_one_letter_sequence_uniprot_id', 'molecule_one_letter_sequence_uniprot_id', 'TEXT'], - ['molecule_two_letter_sequence', 'molecule_two_letter_sequence', 'TEXT'], - ['molecule_two_letter_sequence_uniprot_id', 'molecule_two_letter_sequence_uniprot_id', 'TEXT'], - - ['CrystalName_of_pandda_input', 'CrystalName_of_pandda_input', 'TEXT'], - - ['pdbx_starting_model', 'pdbx_starting_model', 'TEXT'], - ['data_integration_software', 'data_integration_software', 'TEXT'], - ['phasing_software', 'phasing_software', 'TEXT'], - - ['LastUpdated', 'LastUpdated', 'TEXT'], - ['LastUpdated_by', 'LastUpdated_by', 'TEXT'] - ] - - - - self.data_collection_columns = [ - ['ID', 'ID', 'INTEGER PRIMARY KEY'], - ['CrystalName', 'Sample ID', 'TEXT', 0], - ['ProteinName', 'ProteinName', 'TEXT', 1], - - ['DataCollectionVisit', 'Visit', 'TEXT', 0], - ['DataCollectionRun', 'Run', 'TEXT', 0], - ['DataCollectionBeamline', 'Beamline', 'TEXT', 0], - ['DataCollectionOutcome', 'DataCollection\nOutcome', 'TEXT', 1], - ['DataCollectionDate', 'Data Collection\nDate', 'TEXT', 1], - ['DataCollectionWavelength', 'Wavelength', 'TEXT', 0], - ['DataCollectionPinBarcode', 'GDA\nBarcode', 'TEXT', 1], - - ['DataCollectionCrystalImage1', 'img1', 'TEXT', 1], - ['DataCollectionCrystalImage2', 'img2', 'TEXT', 1], - ['DataCollectionCrystalImage3', 'img3', 'TEXT', 1], - ['DataCollectionCrystalImage4', 'img4', 'TEXT', 1], - - ['DataProcessingPathToImageFiles', 'Path to diffraction\nimage files', 'TEXT', 1], - ['DataProcessingProgram', 'Program', 'TEXT', 1], - ['DataProcessingSpaceGroup', 'DataProcessing\nSpaceGroup', 'TEXT', 1], - ['DataProcessingUnitCell', 'DataProcessing\nUnitCell', 'TEXT', 0], - ['DataProcessingAutoAssigned', 'auto-assigned', 'TEXT', 0], - ['DataProcessingA', 'DataProcessing\nA', 'TEXT', 0], - ['DataProcessingB', 'DataProcessing\nB', 'TEXT', 0], - ['DataProcessingC', 'DataProcessing\nC', 'TEXT', 0], - ['DataProcessingAlpha', 'DataProcessing\nAlpha', 'TEXT', 0], - ['DataProcessingBeta', 'DataProcessing\nBeta', 'TEXT', 0], - ['DataProcessingGamma', 'DataProcessing\nGamma', 'TEXT', 0], - ['DataProcessingResolutionOverall', 'Resolution\nOverall', 'TEXT', 0], - ['DataProcessingResolutionLow', 'Resolution\nLow', 'TEXT', 0], - ['DataProcessingResolutionLowInnerShell', 'Resolution\nLow (Inner Shell)', 'TEXT', 0], - ['DataProcessingResolutionHigh', 'Resolution\nHigh', 'TEXT', 1], - ['DataProcessingResolutionHigh15sigma', 'Resolution\n[Mn = 1.5]', 'TEXT', 1], - ['DataProcessingResolutionHigh20sigma', 'Resolution\n[Mn = 2.0]', 'TEXT', 1], - ['DataProcessingResolutionHighOuterShell', 'Resolution\nHigh (Outer Shell)', 'TEXT', 0], - ['DataProcessingRmergeOverall', 'Rmerge\nOverall', 'TEXT', 1], - ['DataProcessingRmergeLow', 'Rmerge\nLow', 'TEXT', 1], - ['DataProcessingRmergeHigh', 'Rmerge\nHigh', 'TEXT', 1], - ['DataProcessingIsigOverall', 'Mn\nOverall', 'TEXT', 1], - ['DataProcessingIsigLow', 'Mn\nLow', 'TEXT', 1], - ['DataProcessingIsigHigh', 'Mn\nHigh', 'TEXT', 1], - ['DataProcessingCompletenessOverall', 'Completeness\nOverall', 'TEXT', 1], - ['DataProcessingCompletenessLow', 'Completeness\nLow', 'TEXT', 1], - ['DataProcessingCompletenessHigh', 'Completeness\nHigh', 'TEXT', 1], - ['DataProcessingMultiplicityOverall', 'Multiplicity\nOverall', 'TEXT', 1], - ['DataProcessingMultiplicityLow', 'Multiplicity\nLow', 'TEXT', 1], - ['DataProcessingMultiplicityHigh', 'Multiplicity\nHigh', 'TEXT', 1], - ['DataProcessingCChalfOverall', 'CC(1/2)\nOverall', 'TEXT', 1], - ['DataProcessingCChalfLow', 'CC(1/2)\nLow', 'TEXT', 1], - ['DataProcessingCChalfHigh', 'CC(1/2)\nHigh', 'TEXT', 1], - ['DataProcessingPathToLogfile', 'DataProcessingPathToLogfile', 'TEXT', 1], - ['DataProcessingPathToMTZfile', 'DataProcessingPathToMTZfile', 'TEXT', 1], - ['DataProcessingLOGfileName', 'DataProcessingLOGfileName', 'TEXT', 0], - ['DataProcessingMTZfileName', 'DataProcessingMTZfileName', 'TEXT', 0], - ['DataProcessingDirectoryOriginal', 'DataProcessingDirectoryOriginal', 'TEXT', 0], - ['DataProcessingUniqueReflectionsOverall', 'Unique Reflections\nOverall', 'TEXT', 1], - ['DataProcessingLattice', 'DataProcessing\nLattice', 'TEXT', 0], - ['DataProcessingPointGroup', 'DataProcessing\nPointGroup', 'TEXT', 0], - ['DataProcessingUnitCellVolume', 'DataProcessing\nUnit Cell Volume', 'TEXT', 0], - ['DataProcessingAlert', 'DataProcessing\nAlert', 'TEXT', 0], - ['DataProcessingScore', 'DataProcessing\nScore', 'TEXT', 1], - ['DataProcessingStatus', 'DataProcessing\nStatus', 'TEXT', 1], - ['LastUpdated', 'LastUpdated', 'TEXT', 0], - ['LastUpdated_by', 'LastUpdated_by', 'TEXT', 0] - ] - - - self.zenodo_table_columns = [ - ['ID', 'ID', 'INTEGER PRIMARY KEY' ], - ['DimplePANDDApath', 'DimplePANDDApath', 'TEXT' ], - ['ZenodoTitle', 'ZenodoTitle', 'TEXT' ], - ['ZenodoHTTPS', 'ZenodoHTTPS', 'TEXT' ], - ['ZenodoDOI', 'ZenodoDOI', 'TEXT' ], - ['LastUpdated', 'LastUpdated', 'TEXT' ], - ['LastUpdated_by', 'LastUpdated_by', 'TEXT' ] - ] - - self.label_table_columns = [ - ['ID', 'ID', 'INTEGER PRIMARY KEY' ], - ['Label', 'Label', 'TEXT' ], - ['Description', 'Description', 'TEXT' ], - ] - - - def columns_not_to_display(self): - do_not_display = [] - for column in self.column_list: - if column[3]==0: - do_not_display.append(column[1]) - return do_not_display - - def get_empty_db_dict(self): - db_dict={} - for column in self.column_list: - if column[0] != 'ID': - db_dict[column[0]]='' - return db_dict - - def create_missing_columns(self): - existing_columns=[] - connect=sqlite3.connect(self.data_source_file) - connect.row_factory = sqlite3.Row - cursor = connect.cursor() - - tableDict = { 'mainTable': self.column_list, - 'panddaTable': self.pandda_table_columns, - 'depositTable': self.deposition_table_columns, - 'collectionTable': self.data_collection_columns, - 'zenodoTable': self.zenodo_table_columns, - 'labelTable': self.label_table_columns } - - for table in tableDict: - cursor.execute("create table if not exists "+table+" (ID INTEGER);") - existing_columns = [] - cursor.execute("SELECT * FROM "+table) - for column in cursor.description: - existing_columns.append(column[0]) - for column in tableDict[table]: - if column[0] not in existing_columns: - cursor.execute("alter table " + table + " add column '" + column[0] + "' '" + column[2] + "'") - connect.commit() - if table == 'labelTable': - cursor.execute('select ID from labelTable') - id = cursor.fetchall() - if id == []: - for idx in range(5): - cursor.execute("insert into labelTable (ID) Values (%s)" %str(idx+1)) - -# existing_columns=[] -# connect=sqlite3.connect(self.data_source_file) -# connect.row_factory = sqlite3.Row -# cursor = connect.cursor() -# cursor.execute("SELECT * FROM mainTable") -# for column in cursor.description: -# existing_columns.append(column[0]) -# for column in self.column_list: -# if column[0] not in existing_columns: -# cursor.execute("alter table mainTable add column '"+column[0]+"' '"+column[2]+"'") -# connect.commit() -# # create PANDDA table if not exists -# cursor.execute("create table if not exists panddaTable (ID INTEGER);") -# existing_columns=[] -# cursor.execute("SELECT * FROM panddaTable") -# for column in cursor.description: -# existing_columns.append(column[0]) -# for column in self.pandda_table_columns: -# if column[0] not in existing_columns: -# cursor.execute("alter table panddaTable add column '"+column[0]+"' '"+column[2]+"'") -# connect.commit() -# # create DEPOSIT table if not exists -# cursor.execute("create table if not exists depositTable (ID INTEGER);") -# existing_columns=[] -# cursor.execute("SELECT * FROM depositTable") -# for column in cursor.description: -# existing_columns.append(column[0]) -# for column in self.deposition_table_columns: -# if column[0] not in existing_columns: -# cursor.execute("alter table depositTable add column '"+column[0]+"' '"+column[2]+"'") -# connect.commit() - - - def return_column_list(self): - return self.column_list - - - def create_empty_data_source_file(self): - - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - with connect: - cursor = connect.cursor() - cursor.execute("CREATE TABLE mainTable("+self.column_list[0][0]+' '+self.column_list[0][2]+")") - for i in range(1,len(self.column_list)): - cursor.execute("alter table mainTable add column '"+self.column_list[i][0]+"' '"+self.column_list[i][2]+"'") - connect.commit() - # Don't need to create panddaTable at this point, because table will be created by create_missing_columns - # which is called the first time a data source in specified in XCE -# with connect: -# cursor = connect.cursor() -# cursor.execute("CREATE TABLE panddaTable("+self.pandda_table_columns[0][0]+' '+self.pandda_table_columns[0][2]+")") -# for i in range(1,len(self.pandda_table_columns)): -# cursor.execute("alter table mainTable add column '"+self.pandda_table_columns[i][0]+"' '"+self.pandda_table_columns[i][2]+"'") -# connect.commit() - - def get_all_samples_in_data_source_as_list(self): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("SELECT CrystalName FROM mainTable") - existing_samples_in_db=[] - samples = cursor.fetchall() - for sample in samples: - existing_samples_in_db.append(str(sample[0])) - return existing_samples_in_db - - def execute_statement(self,cmd): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute(cmd) - output=cursor.fetchall() - connect.commit() - return output - - def get_db_dict_for_sample(self,sampleID): - db_dict={} - header=[] - data=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select * from mainTable where CrystalName='{0!s}';".format(sampleID)) - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - for n,item in enumerate(data[0]): - db_dict[header[n]]=str(item) - return db_dict - - def get_deposit_dict_for_sample(self,sampleID): - db_dict={} - header=[] - data=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - if sampleID == 'ground-state': # just select first row in depositTable - cursor.execute("SELECT * FROM depositTable ORDER BY ROWID ASC LIMIT 1;") - else: - cursor.execute("select * from depositTable where CrystalName='{0!s}';".format(sampleID)) - - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - try: - for n,item in enumerate(data[0]): - db_dict[header[n]]=str(item) - except IndexError: - pass - return db_dict - - def get_zenodo_dict_for_pandda_analysis(self,panddaPath): - db_dict={} - header=[] - data=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - try: - cursor.execute("select * from zenodoTable where DimplePANDDApath='{0!s}';".format(panddaPath)) - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - try: - for n,item in enumerate(data[0]): - db_dict[header[n]]=str(item) - except IndexError: - pass - except sqlite3.OperationalError: - db_dict = {} - return db_dict - - - - def get_db_pandda_dict_for_sample_and_site(self,sampleID,site_index): - db_dict={} - header=[] - data=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select * from panddaTable where CrystalName='{0!s}' and PANDDA_site_index='{1!s}';".format(sampleID, site_index)) - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - for n,item in enumerate(data[0]): - db_dict[header[n]]=str(item) - return db_dict - - def get_db_pandda_dict_for_sample_and_site_and_event(self,sampleID,site_index,event_index): - db_dict={} - header=[] - data=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select * from panddaTable where CrystalName='{0!s}' and PANDDA_site_index='{1!s}' and PANDDA_site_event_index='{2!s}' and PANDDA_site_ligand_placed='True';".format(sampleID, site_index, event_index)) - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - for n,item in enumerate(data[0]): - db_dict[header[n]]=str(item) - return db_dict - - def check_if_sample_exists_in_data_source(self,sampleID): - sample_exists=False - existing_samples_in_db=self.get_all_samples_in_data_source_as_list() - if sampleID in existing_samples_in_db: - sample_exists=True - return sample_exists - - def import_csv_file(self,csv_file): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - available_columns=[] - cursor.execute("SELECT * FROM mainTable") - for column in cursor.description: # only update existing columns in data source - available_columns.append(column[0]) - with open(csv_file,'rb') as csv_import: # `with` statement available in 2.5+ - # csv.DictReader uses first line in file for column headings by default - csv_dict = csv.DictReader(csv_import) # comma is default delimiter - for line in csv_dict: - sampleID=line['CrystalName'] - if str(sampleID).replace(' ','')=='': - continue - if self.check_if_sample_exists_in_data_source(sampleID): - update_string='' - for key,value in line.iteritems(): - if key=='ID' or key=='CrystalName': - continue - if key not in available_columns: - continue - # this is how I had it originally, so it would ignore empty fields - # the problem is that if the user wants to set all values to Null, - # if will ignore it and leave the inital value in the datasource -# if not str(value).replace(' ','')=='': # ignore if nothing in csv field -# update_string+=str(key)+'='+"'"+str(value)+"'"+',' -# print "UPDATE mainTable SET "+update_string[:-1]+" WHERE CrystalName="+"'"+sampleID+"';" -# cursor.execute("UPDATE mainTable SET "+update_string[:-1]+" WHERE CrystalName="+"'"+sampleID+"';") - # now try this instead; not sure what will break now... - update_string+=str(key)+'='+"'"+str(value)+"'"+',' -# print "UPDATE mainTable SET "+update_string[:-1]+" WHERE CrystalName="+"'"+sampleID+"';" - cursor.execute("UPDATE mainTable SET "+update_string[:-1]+" WHERE CrystalName="+"'"+sampleID+"';") - else: - column_string='' - value_string='' - for key,value in line.iteritems(): - if key=='ID': - continue - if key not in available_columns: - continue - if not str(value).replace(' ','')=='': # ignore if nothing in csv field - value_string+="'"+value+"'"+',' - column_string+=key+',' -# print sampleID -# print "INSERT INTO mainTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");" - cursor.execute("INSERT INTO mainTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");") - - connect.commit() - - def update_data_source(self,sampleID,data_dict): - print 'here' - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - - # need to do this since some older sqlite files contain a columnn called - # DataProcessingResolutionHigh1.5sigma - # and this does not go down well with the SQLite statement below - removeKey='' - for key in data_dict: - if '.5' in key: - removeKey=key - break - if removeKey != '': - del data_dict[removeKey] - - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - update_string='' - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string+=str(key)+'='+"'"+str(value)+"'"+',' - else: - update_string+=str(key)+' = null,' - if update_string != '': -# print "UPDATE mainTable SET "+update_string[:-1]+" WHERE CrystalName="+"'"+sampleID+"'" - cursor.execute("UPDATE mainTable SET "+update_string[:-1]+" WHERE CrystalName="+"'"+sampleID+"'") - connect.commit() - - def update_panddaTable(self,sampleID,site_index,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - update_string='' - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName' or key=='PANDDA_site_index': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string+=str(key)+'='+"'"+str(value)+"'"+',' - else: - update_string+=str(key)+' = null,' - if update_string != '': - cursor.execute("UPDATE panddaTable SET "+update_string[:-1]+" WHERE CrystalName='{0!s}' and PANDDA_site_index='{1!s}'".format(sampleID, site_index)) - connect.commit() - - def update_site_event_panddaTable(self,sampleID,site_index,event_index,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - update_string='' - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName' or key=='PANDDA_site_index' or key=='PANDDA_site_event_index': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string+=str(key)+'='+"'"+str(value)+"'"+',' - else: - update_string+=str(key)+' = null,' - if update_string != '': - cursor.execute("UPDATE panddaTable SET "+update_string[:-1]+" WHERE CrystalName='{0!s}' and PANDDA_site_index='{1!s}' and PANDDA_site_event_index='{2!s}'".format(sampleID, site_index, event_index)) - connect.commit() - - def update_depositTable(self,sampleID,structure_type,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - update_string='' - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName' or key=='StructureType': - continue - if not str(value).replace(' ','')=='': # ignore empty fields -# update_string+=str(key)+'='+"'"+str(value)+"'"+',' -# update_string+=str(key)+'='+'"'+str(value)+'"'+',' - update_string+=str(key)+'='+'"'+str(value).replace('\r','').replace('\n','')+'"'+',' - else: - update_string+=str(key)+' = null,' - if update_string != '': -# print '-->',"UPDATE depositTable SET "+update_string[:-1]+" WHERE CrystalName='{0!s}' and StructureType='{1!s}'".format(sampleID, structure_type) -# cursor.execute("UPDATE depositTable SET "+update_string[:-1]+" WHERE CrystalName='{0!s}' and StructureType='{1!s}'".format(sampleID, structure_type)) - cursor.execute('UPDATE depositTable SET '+update_string[:-1]+' WHERE CrystalName="{0!s}" and StructureType="{1!s}"'.format(sampleID, structure_type)) - connect.commit() - - - def update_specified_table(self,sampleID,data_dict,table): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - update_string='' - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string+=str(key)+'='+"'"+str(value)+"'"+',' - if update_string != '': - cursor.execute("UPDATE "+table+" SET "+update_string[:-1]+" WHERE CrystalName="+"'"+sampleID+"'") - connect.commit() - - def update_insert_data_source(self,sampleID,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute('Select CrystalName FROM mainTable') - available_columns=[] - cursor.execute("SELECT * FROM mainTable") - for column in cursor.description: # only update existing columns in data source - available_columns.append(column[0]) - if self.check_if_sample_exists_in_data_source(sampleID): - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string=str(key)+'='+"'"+str(value)+"'" - cursor.execute("UPDATE mainTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"';") - else: - column_string='CrystalName'+',' - value_string="'"+sampleID+"'"+',' - for key in data_dict: - value=data_dict[key] - if key=='ID': - continue - if key not in available_columns: - continue - if not str(value).replace(' ','')=='': # ignore if nothing in csv field - value_string+="'"+str(value)+"'"+',' - column_string+=key+',' - cursor.execute("INSERT INTO mainTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");") - connect.commit() - - - - def update_insert_panddaTable(self,sampleID,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute('Select CrystalName,PANDDA_site_index FROM panddaTable') -# available_columns=[] -# cursor.execute("SELECT * FROM panddaTable") -# for column in cursor.description: # only update existing columns in data source -# available_columns.append(column[0]) - samples_sites_in_table=[] - tmp=cursor.fetchall() - for item in tmp: - line=[x.encode('UTF8') for x in list(item)] - samples_sites_in_table.append(line) - - found_sample_site=False - for entry in samples_sites_in_table: - if entry[0]==sampleID and entry[1]==data_dict['PANDDA_site_index']: - found_sample_site=True - - if found_sample_site: - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName' or key=='PANDDA_site_index': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string=str(key)+'='+"'"+str(value)+"'" -# print "UPDATE panddaTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"' and PANDDA_site_index is '"+data_dict['PANDDA_site_index']+"';" - cursor.execute("UPDATE panddaTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"' and PANDDA_site_index is '"+data_dict['PANDDA_site_index']+"';") - else: - column_string='' - value_string='' - for key in data_dict: - value=data_dict[key] - if key=='ID': - continue -# if key not in available_columns: -# continue - if not str(value).replace(' ','')=='': # ignore if nothing in csv field - value_string+="'"+str(value)+"'"+',' - column_string+=key+',' - print "INSERT INTO panddaTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");" - cursor.execute("INSERT INTO panddaTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");") - connect.commit() - - def update_insert_any_table(self,table,data_dict,condition_dict): - data_dict['LastUpdated'] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by'] = getpass.getuser() - connect = sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - - # columns - columns = '' - for c in condition_dict: - columns+=c+',' - - # condition - condition_string = '' - for key in condition_dict: - condition = condition_dict[key] - condition_string += str(key) + '=' + "'" + str(condition) + "' and " - - cursor.execute('Select %s FROM %s where %s' %(columns[:-1],table,condition_string[:-5])) - - tmp = cursor.fetchall() - if not tmp: - data_dict.update(condition_dict) - value_string='' - column_string='' - for key in data_dict: - value = data_dict[key] - value_string += "'" + str(value) + "'" + ',' - column_string += key + ',' - cursor.execute("INSERT INTO "+table+" (" + column_string[:-1] + ") VALUES (" + value_string[:-1] + ");") - else: - update_string='' - for key in data_dict: - value = data_dict[key] - update_string += str(key) + '=' + "'" + str(value) + "'," - cursor.execute( - "UPDATE " + table + - " SET " + update_string[:-1] + - " WHERE " + condition_string[:-5] + ";") - connect.commit() - - - def update_insert_site_event_panddaTable(self,sampleID,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute('Select CrystalName,PANDDA_site_index,PANDDA_site_event_index FROM panddaTable') -# available_columns=[] -# cursor.execute("SELECT * FROM panddaTable") -# for column in cursor.description: # only update existing columns in data source -# available_columns.append(column[0]) - samples_sites_in_table=[] - tmp=cursor.fetchall() - for item in tmp: - line=[x.encode('UTF8') for x in list(item)] - samples_sites_in_table.append(line) - - found_sample_site=False - for entry in samples_sites_in_table: - if entry[0]==sampleID and entry[1]==data_dict['PANDDA_site_index'] and entry[2]==data_dict['PANDDA_site_event_index']: - found_sample_site=True - - if found_sample_site: - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName' or key=='PANDDA_site_index' or key=='PANDDA_site_event_index': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string=str(key)+'='+"'"+str(value)+"'" -# print "UPDATE panddaTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"' and PANDDA_site_index is '"+data_dict['PANDDA_site_index']+"';" - cursor.execute("UPDATE panddaTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"' and PANDDA_site_index is '"+data_dict['PANDDA_site_index']+"' and PANDDA_site_event_index is '"+data_dict['PANDDA_site_event_index']+"';") - else: - column_string='' - value_string='' - for key in data_dict: - value=data_dict[key] - if key=='ID': - continue -# if key not in available_columns: -# continue - if not str(value).replace(' ','')=='': # ignore if nothing in csv field - value_string+="'"+str(value)+"'"+',' - column_string+=key+',' - print "INSERT INTO panddaTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");" - cursor.execute("INSERT INTO panddaTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");") - connect.commit() - - - - def update_insert_depositTable(self,sampleID,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - available_columns=[] - cursor.execute("SELECT * FROM depositTable") - for column in cursor.description: # only update existing columns in data source - available_columns.append(column[0]) - - - cursor.execute('Select CrystalName FROM depositTable') - samples_in_table=[] - tmp=cursor.fetchall() - for item in tmp: - line=[x.encode('UTF8') for x in list(item)] -# print 'a',item -# print 'b',str(item) -# print 'c',line -# print 'd',line[0] -# print 'e',str(line[0]) - if str(item) not in samples_in_table: samples_in_table.append(str(line[0])) -# samples_in_table.append(line) - - - - if sampleID in samples_in_table: - for key in data_dict: - value=data_dict[key] - if key=='ID' or key=='CrystalName': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string=str(key)+'='+"'"+str(value)+"'" - print "UPDATE depositTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"';" - cursor.execute("UPDATE depositTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"';") - else: - column_string='CrystalName'+',' - value_string="'"+sampleID+"'"+',' - for key in data_dict: - value=data_dict[key] - if key=='ID': - continue - if key not in available_columns: - continue - if not str(value).replace(' ','')=='': # ignore if nothing in csv field - value_string+="'"+str(value)+"'"+',' - column_string+=key+',' - print "INSERT INTO depositTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");" - cursor.execute("INSERT INTO depositTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");") - connect.commit() - - - - def update_insert_not_null_fields_only(self,sampleID,data_dict): - data_dict['LastUpdated']=str(datetime.now().strftime("%Y-%m-%d %H:%M")) - data_dict['LastUpdated_by']=getpass.getuser() - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute('Select CrystalName FROM mainTable') - available_columns=[] - cursor.execute("SELECT * FROM mainTable") - for column in cursor.description: # only update existing columns in data source - available_columns.append(column[0]) - if self.check_if_sample_exists_in_data_source(sampleID): - for key in data_dict: - value=data_dict[key] -# print value - if key=='ID' or key=='CrystalName': - continue - if not str(value).replace(' ','')=='': # ignore empty fields - update_string=str(key)+'='+"'"+str(value)+"'" -# cursor.execute("UPDATE mainTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"' and "+str(key)+" is null;") - cursor.execute("UPDATE mainTable SET "+update_string+" WHERE CrystalName="+"'"+sampleID+"' and ("+str(key)+" is null or "+str(key)+"='');") - else: - column_string='CrystalName'+',' - value_string="'"+sampleID+"'"+',' - for key in data_dict: - value=data_dict[key] - if key=='ID': - continue - if key not in available_columns: - continue - if not str(value).replace(' ','')=='': # ignore if nothing in csv field - value_string+="'"+str(value)+"'"+',' - column_string+=key+',' - cursor.execute("INSERT INTO mainTable ("+column_string[:-1]+") VALUES ("+value_string[:-1]+");") - connect.commit() - - def get_value_from_field(self,sampleID,column): - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute("SELECT "+column+" FROM mainTable WHERE CrystalName='"+sampleID+"';") - return cursor.fetchone() - - def export_to_csv_file(self,csv_file): - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute("SELECT * FROM mainTable") - header=() - for column in cursor.description: - header+=(column[0],) - rows = cursor.fetchall() - csvWriter = csv.writer(open(csv_file, "w")) - csvWriter.writerows([header]+rows) - - -# def load_samples_from_data_source(self): -# header=[] -# data=[] -# connect=sqlite3.connect(self.data_source_file) -# cursor = connect.cursor() -# cursor.execute("SELECT * FROM mainTable") -# for column in cursor.description: -# header.append(column[0]) -# data = cursor.fetchall() -# return ([header,data]) - - def load_samples_from_data_source(self): - header=[] - data=[] - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute("SELECT * FROM mainTable") - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - return header,data - - - - - -# def get_samples_for_coot(self,RefinementOutcome,pandda_site): -# sample_list_for_coot=[] -# connect=sqlite3.connect(self.data_source_file) -# cursor = connect.cursor() -# -# if RefinementOutcome=='0 - All Datasets': -# outcome = " not null " -# else: -# outcome = " '%s' " %RefinementOutcome -# -# if int(pandda_site) > 0: -# sqlite = ( -# "select" -# " mainTable.CrystalName," -# " mainTable.CompoundCode," -# " mainTable.RefinementCIF," -# " mainTable.RefinementMTZfree," -# " mainTable.RefinementPathToRefinementFolder," -# " panddaTable.RefinementOutcome, " -# " panddaTable.PANDDA_site_event_map," -# " panddaTable.PANDDA_site_confidence," -# " panddaTable.PANDDA_site_x," -# " panddaTable.PANDDA_site_y," -# " panddaTable.PANDDA_site_z," -# " panddaTable.PANDDA_site_initial_model," -# " panddaTable.PANDDA_site_initial_mtz," -# " panddaTable.PANDDA_site_spider_plot, " -# " panddaTable.PANDDA_site_index " -# "from mainTable inner join panddaTable on mainTable.CrystalName = panddaTable.CrystalName " -# "where panddaTable.PANDDA_site_index is '%s'" %pandda_site+ -# " and panddaTable.PANDDA_site_ligand_placed is 'True'" -# " and panddaTable.RefinementOutcome is %s;" %outcome -# ) -# -# else: -# sqlite = ( -# "select" -# " CrystalName," -# " CompoundCode," -# " RefinementCIF," -# " RefinementMTZfree," -# " RefinementPathToRefinementFolder," -# " RefinementOutcome " -# "from mainTable " -# "where RefinementOutcome is %s;" %outcome -# ) -# -# cursor.execute(sqlite) -# -# tmp = cursor.fetchall() -# for item in tmp: -# tmpx=[] -# for i in list(item): -# if i==None: -# tmpx.append('None') -# else: -# tmpx.append(i) -# line=[x.encode('UTF8') for x in tmpx] -# sample_list_for_coot.append(line) -# -# return sample_list_for_coot - - def get_pandda_info_for_coot(self,xtalID,pandda_site): - pandda_info_for_coot=[] - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - - sqlite = ( - "select" - " PANDDA_site_event_map," - " PANDDA_site_x," - " PANDDA_site_y," - " PANDDA_site_z," - " PANDDA_site_spider_plot " - "from panddaTable " - "where " - " CrystalName is '%s'" %xtalID+ - " and PANDDA_site_index is '{0!s}';".format(pandda_site) - ) - - cursor.execute(sqlite) - - tmp = cursor.fetchall() - for item in tmp: - tmpx=[] - for i in list(item): - if i is None: - tmpx.append('None') - else: - tmpx.append(i) - line=[x.encode('UTF8') for x in tmpx] - pandda_info_for_coot.append(line) - - return pandda_info_for_coot - - - - def get_todo_list_for_coot(self,RefinementOutcome,pandda_site): - sample_list_for_coot=[] - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - - if RefinementOutcome=='0 - All Datasets': - outcome = " not null " - else: - outcome = " '{0!s}' ".format(RefinementOutcome) - - if int(pandda_site) > 0: -# sqlite = ( -# "select" -# " mainTable.CrystalName," -# " mainTable.CompoundCode," -# " mainTable.RefinementCIF," -# " mainTable.RefinementMTZfree," -# " mainTable.RefinementPathToRefinementFolder," -# " panddaTable.RefinementOutcome, " -# " panddaTable.PANDDA_site_confidence " -# "from mainTable inner join panddaTable on mainTable.CrystalName = panddaTable.CrystalName " -# "where panddaTable.PANDDA_site_index is '%s'" %pandda_site+ -# " and panddaTable.PANDDA_site_ligand_placed is 'True'" -# " and panddaTable.RefinementOutcome is %s;" %outcome -# ) - sqlite = ( - "select" - " mainTable.CrystalName," - " mainTable.CompoundCode," - " mainTable.RefinementCIF," - " mainTable.RefinementMTZfree," - " mainTable.RefinementPathToRefinementFolder," - " panddaTable.RefinementOutcome, " - " panddaTable.PANDDA_site_confidence " - "from mainTable inner join panddaTable on mainTable.CrystalName = panddaTable.CrystalName " - "where panddaTable.PANDDA_site_index is '%s'" %pandda_site+ - " and panddaTable.PANDDA_site_ligand_placed is 'True'" - " and panddaTable.RefinementOutcome like "+outcome.split()[0]+"%';" - ) -# sqlite = ( -# "select" -# " mainTable.CrystalName," -# " mainTable.CompoundCode," -# " mainTable.RefinementCIF," -# " mainTable.RefinementMTZfree," -# " mainTable.RefinementPathToRefinementFolder," -# " panddaTable.RefinementOutcome, " -# " panddaTable.PANDDA_site_confidence " -# "from mainTable inner join panddaTable on mainTable.CrystalName = panddaTable.CrystalName " -# "where panddaTable.PANDDA_site_index is '%s'" %pandda_site+ -# " and panddaTable.RefinementOutcome like "+outcome.split()[0]+"%';" -# ) - else: - sqlite = ( - "select" - " CrystalName," - " CompoundCode," - " RefinementCIF," - " RefinementMTZfree," - " RefinementPathToRefinementFolder," - " RefinementOutcome," - " RefinementLigandConfidence " - "from mainTable " - "where RefinementOutcome is %s and DimpleRfree is not Null;" %outcome - ) - cursor.execute(sqlite) - - tmp = cursor.fetchall() - for item in tmp: - tmpx=[] - for i in list(item): - if i is None: - tmpx.append('None') - else: - tmpx.append(i) - line=[x.encode('UTF8') for x in tmpx] - sample_list_for_coot.append(line) - - return sample_list_for_coot - - - def get_todoList_for_coot(self,RefinementOutcome): - sample_list_for_coot=[] - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - - if RefinementOutcome=='0 - All Datasets': - outcome = " not null " - else: - outcome = " '{0!s}' ".format(RefinementOutcome) - - sqlite = ( - "select" - " CrystalName," - " CompoundCode," - " RefinementCIF," - " RefinementMTZfree," - " RefinementPathToRefinementFolder," - " RefinementOutcome," - " RefinementLigandConfidence " - "from mainTable " - "where RefinementOutcome is %s and (DimpleRfree is not Null or RefinementRfree is not Null) order by CrystalName ASC;" %outcome - ) - - cursor.execute(sqlite) - - tmp = cursor.fetchall() - for item in tmp: - tmpx=[] - for i in list(item): - if i is None: - tmpx.append('None') - else: - tmpx.append(i) - line=[x.encode('UTF8') for x in tmpx] - sample_list_for_coot.append(line) - - crystalDict={} - for entry in sample_list_for_coot: - if entry[0] not in crystalDict: - sqlite = ( "select" - " PANDDA_site_event_map," - " PANDDA_site_x," - " PANDDA_site_y," - " PANDDA_site_z," - " PANDDA_site_spider_plot," - " PANDDA_site_index," - " PANDDA_site_event_index," - " PANDDA_site_confidence," - " PANDDA_site_name," - " PANDDA_site_InspectConfidence," - " PANDDA_site_interesting," - " PANDDA_site_event_comment " - "from panddaTable " - "where " - " CrystalName is '%s';" %entry[0] ) - cursor.execute(sqlite) - tmp = cursor.fetchall() - if tmp: - crystalDict[entry[0]]=[] - for item in tmp: - print [entry[0], str(item[0]),str(item[1]),str(item[2]),str(item[3]),str(item[4]),str(item[5]),str(item[6]),str(item[7]),str(item[8]),str(item[9]),str(item[10]),str(item[11]) ] - crystalDict[entry[0]].append( [ str(item[0]),str(item[1]),str(item[2]),str(item[3]),str(item[4]),str(item[5]),str(item[6]),str(item[7]),str(item[8]),str(item[9]),str(item[10]),str(item[11]) ]) - - return sample_list_for_coot,crystalDict - - - - - def translate_xce_column_list_to_sqlite(self,column_list): - out_list=[] - for item in column_list: - if item.startswith('Exclude'): - out_list.append(['Exclude']) - if item.startswith('Ignore'): - out_list.append(['Ignore']) -# if item.startswith('img'): -# out_list.append([item,item]) -# continue - if item.startswith('Show'): - out_list.append([item,item]) - continue - if item.startswith('Run\nDimple'): - out_list.append([item,item]) - continue - if item.startswith('Select'): - out_list.append([item,item]) - continue - if item.startswith('Run\nxia2'): - out_list.append([item,item]) - continue - if item.startswith('Dataset ID'): - out_list.append([item,item]) - continue - if item.startswith('Reference\nSpaceGroup'): - out_list.append([item,item]) - continue - if item.startswith('Difference\nUC Volume (%)'): - out_list.append([item,item]) - continue - if item.startswith('Reference File'): - out_list.append([item,item]) - continue - if item.startswith('PanDDA site details'): - out_list.append([item,item]) - continue - for entry in self.column_list: - if entry[1]==item: - out_list.append([item,entry[0]]) - break - return out_list - - def get_list_of_pandda_sites_for_coot(self): - site_list=[ ['0','any site'] ] - sqlite = ( - 'select distinct' - ' panddaTable.PANDDA_site_index,' - ' panddaTable.PANDDA_site_name ' - 'from panddaTable ' - 'order by cast (panddaTable.PANDDA_site_index as integer) ASC;' - ) - - print 'data source',self.data_source_file - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute(sqlite) - tmp=cursor.fetchall() - for item in tmp: -# print item -# print str(item[0]) -# print str(item[1]) -# line=[x.encode('UTF8') for x in list(item)] - site_list.append([str(item[0]),str(item[1])]) - - return site_list - - def export_csv_for_WONKA(self): - SQLite = ( "select" - " panddaTable.PANDDA_site_ligand_resname," - " panddaTable.PANDDA_site_ligand_sequence_number," - " panddaTable.PANDDA_site_ligand_chain," - " panddaTable.RefinementOutcome," - " mainTable.CompoundSMILES," - " mainTable.RefinementBoundConformation," - " panddaTable.PANDDA_site_initial_mtz," - " panddaTable.PANDDA_site_event_map," - " panddaTable.CrystalName," - " mainTable.CompoundCode " - "from" - " mainTable inner join panddaTable on mainTable.CrystalName = panddaTable.CrystalName " - "where" - " (panddaTable.RefinementOutcome like '3%' or panddaTable.RefinementOutcome like '4%' or panddaTable.RefinementOutcome like '5%')" ) - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute(SQLite) - header=() - for column in cursor.description: - header+=(column[0],) - rows = cursor.fetchall() - csvWriter = csv.writer(open('for_wonka.csv', "w")) - csvWriter.writerows([header]+rows) - - def create_missing_apo_records_in_depositTable(self,xce_logfile): - Logfile=XChemLog.updateLog(xce_logfile) - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute("select panddaTable.ApoStructures from panddaTable where panddaTable.ApoStructures is not Null") - tmp = cursor.fetchall() -# print str(tmp) - apoStructureList=[] - for item in tmp: - for xtal in str(item[0]).split(';'): - if xtal not in apoStructureList: apoStructureList.append(xtal) - if not apoStructureList: - Logfile.insert('no apo structures were assigned to your pandda models') - else: - Logfile.insert('the following datasets were at some point used as apo structures for pandda.analyse: '+str(apoStructureList)) - apoInDB=[] - cursor.execute("select CrystalName from depositTable where StructureType is 'apo'") - tmp = cursor.fetchall() - for xtal in tmp: - Logfile.insert(str(xtal[0])+' exists as entry for apo structure in database') - apoInDB.append(str(xtal[0])) - newEntries='' - for xtal in apoStructureList: - if xtal not in apoInDB: - Logfile.insert('no entry for '+xtal+' in depositTable') - newEntries+="('{0!s}','apo'),".format(xtal) - if newEntries != '': - sqlite='insert into depositTable (CrystalName,StructureType) values {0!s};'.format(newEntries[:-1]) - Logfile.insert('creating new entries with the following SQLite command:\n'+sqlite) - cursor.execute(sqlite) - connect.commit() - - def create_missing_apo_records_for_all_structures_in_depositTable(self,projectDir,xce_logfile): - Logfile=XChemLog.updateLog(xce_logfile) - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - cursor.execute("select CrystalName from depositTable where StructureType is 'apo'") - tmp = cursor.fetchall() -# print str(tmp) - apoStructureList=[] - for item in tmp: - apoStructureList.append(str(item[0])) - - counter=0 # there is a SQLite limit which does not allow to insert more than 500 records at once - newEntries='' - for files in glob.glob(os.path.join(projectDir,'*')): - xtal=files[files.rfind('/')+1:] - if xtal not in apoStructureList: - dimple_pdb=False - dimple_mtz=False - aimless_log=False - if os.path.isfile(os.path.join(files,'dimple.pdb')): - dimple_pdb=True - if os.path.isfile(os.path.join(files,'dimple.mtz')): - dimple_mtz=True - if os.path.isfile(os.path.join(files,xtal+'.log')) or os.path.isfile(os.path.join('aimless.log')): - aimless_log=True - - if dimple_mtz==False or dimple_pdb==False or aimless_log==False: - Logfile.insert('{0!s}: missing files -> dimple.pdb: {1!s}, dimple.mtz: {2!s}, {3!s}.log: {4!s}'.format(xtal, str(dimple_pdb), str(dimple_mtz), xtal, str(aimless_log))) - else: - newEntries+="('{0!s}','apo'),".format(xtal) - counter+=1 - - if counter == 450: # set to 450 to stay well below 500 records limit - sqlite='insert into depositTable (CrystalName,StructureType) values {0!s};'.format(newEntries[:-1]) - Logfile.insert('creating new entries with the following SQLite command:\n'+sqlite) - cursor.execute(sqlite) - connect.commit() - counter=0 - newEntries='' - - if newEntries != '': - sqlite='insert into depositTable (CrystalName,StructureType) values {0!s};'.format(newEntries[:-1]) - Logfile.insert('creating new entries with the following SQLite command:\n'+sqlite) - cursor.execute(sqlite) - connect.commit() - else: - Logfile.insert('did not find any new apo structures') - -# if apoStructureList==[]: -# Logfile.insert('no apo structures were assigned to your pandda models') -# else: -# Logfile.insert('the following datasets were at some point used as apo structures for pandda.analyse: '+str(apoStructureList)) -# apoInDB=[] -# cursor.execute("select CrystalName from depositTable where StructureType is 'apo'") -# tmp = cursor.fetchall() -# for xtal in tmp: -# Logfile.insert(str(xtal[0])+' exists as entry for apo structure in database') -# apoInDB.append(str(xtal[0])) -# newEntries='' -# for xtal in apoStructureList: -# if xtal not in apoInDB: -# Logfile.insert('no entry for '+xtal+' in depositTable') -# newEntries+="('%s','apo')," %xtal -# if newEntries != '': -# sqlite='insert into depositTable (CrystalName,StructureType) values %s;' %newEntries[:-1] -# Logfile.insert('creating new entries with the following SQLite command:\n'+sqlite) -# cursor.execute(sqlite) -# connect.commit() - -# def get_deposit_dict_for_xtal(self,sampleID,structure_type): - - def create_or_remove_missing_records_in_depositTable(self,xce_logfile,xtal,type,db_dict): - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - Logfile=XChemLog.updateLog(xce_logfile) - if type == 'ligand_bound': - cursor.execute("select RefinementOutcome from mainTable where CrystalName is '{0!s}'".format(xtal)) - tmp = cursor.fetchall() - oldRefiStage=str(tmp[0][0]) - Logfile.insert('setting RefinementOutcome field to "'+db_dict['RefinementOutcome']+'" for '+xtal) - self.update_insert_data_source(xtal,db_dict) - elif type == 'ground_state': - cursor.execute("select DimplePANDDApath from depositTable where StructureType is '{0!s}' and DimplePANDDApath is '{1!s}'".format(type,db_dict['DimplePANDDApath'])) - tmp = cursor.fetchall() - if not tmp: - Logfile.insert('entry for ground-state model in depositTable does not exist') - else: - Logfile.warning('entry for ground-state model in depositTable does already exist') - return - - cursor.execute("select CrystalName,StructureType from depositTable where CrystalName is '{0!s}' and StructureType is '{1!s}'".format(xtal, type)) - tmp = cursor.fetchall() - if type == 'ligand_bound': - if not tmp and int(db_dict['RefinementOutcome'].split()[0]) == 5: - sqlite="insert into depositTable (CrystalName,StructureType) values ('{0!s}','{1!s}');".format(xtal, type) - Logfile.insert('creating new entry for '+str(type)+' structure of '+xtal+' in depositTable') - cursor.execute(sqlite) - connect.commit() - else: - if int(db_dict['RefinementOutcome'].split()[0]) < 5: - sqlite="delete from depositTable where CrystalName is '{0!s}' and StructureType is '{1!s}'".format(xtal, type) - Logfile.insert('removing entry for '+str(type)+' structure of '+xtal+' from depositTable') - cursor.execute(sqlite) - connect.commit() - elif type == 'ground_state': - sqlite = "insert into depositTable (CrystalName,StructureType,DimplePANDDApath,PDB_file,MTZ_file) values ('{0!s}','{1!s}','{2!s}','{3!s}','{4!s}');".format(xtal, type, db_dict['DimplePANDDApath'], db_dict['PDB_file'], db_dict['MTZ_file']) - Logfile.insert('creating new entry for ' + str(type) + ' structure of ' + xtal + ' in depositTable') - cursor.execute(sqlite) - connect.commit() - - def remove_selected_apo_structures_from_depositTable(self,xce_logfile,xtalList): - connect=sqlite3.connect(self.data_source_file) - cursor = connect.cursor() - - Logfile=XChemLog.updateLog(xce_logfile) - - Logfile.insert('removing the following apo structures from depositTable') - deleteStrg = "(" - for xtal in xtalList: - Logfile.insert(xtal) - deleteStrg+="Crystalname is '"+xtal+"' or " - deleteStrg=deleteStrg[:-4]+")" - - sqlite="delete from depositTable where {0!s} and StructureType is 'apo'".format(deleteStrg) - Logfile.insert('executing the following SQLite command:\n'+sqlite) - cursor.execute(sqlite) - connect.commit() - - - - -# for item in tmp: -# print item -# for xtal in str(item[0]).split(';'): -# if xtal not in apoStructureList: apoStructureList.append(xtal) -# if apoStructureList==[]: -# Logfile.insert('no apo structures were assigned to your pandda models') -# else: -# Logfile.insert('the following datasets were at some point used as apo structures for pandda.analyse: '+str(apoStructureList)) -# apoInDB=[] -# cursor.execute("select CrystalName from depositTable where StructureType is 'apo'") -# tmp = cursor.fetchall() -# for xtal in tmp: -# Logfile.insert(str(xtal[0])+' exists as entry for apo structure in database') -# apoInDB.append(str(xtal[0])) -# newEntries='' -# for xtal in apoStructureList: -# if xtal not in apoInDB: -# Logfile.insert('no entry for '+xtal+' in depositTable') -# newEntries+="('%s','apo')," %xtal -# if newEntries != '': -# sqlite='insert into depositTable (CrystalName,StructureType) values %s;' %newEntries[:-1] -# Logfile.insert('creating new entries with the following SQLite command:\n'+sqlite) -# cursor.execute(sqlite) -# connect.commit() -# - - def collected_xtals_during_visit(self,visitID): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select CrystalName from collectionTable where DataCollectionVisit = '{0!s}'".format(visitID)) - collectedXtals=[] - samples = cursor.fetchall() - for sample in samples: - if str(sample[0]) not in collectedXtals: - collectedXtals.append(str(sample[0])) - return collectedXtals - - def collected_xtals_during_visit_for_scoring(self,visit): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - xtalList = [] -# if rescore == True: -# cursor.execute("select CrystalName from mainTable where DataCollectionVisit = '%s'" %visit) -# else: -# cursor.execute("select CrystalName from mainTable where DataProcessingAutoAssigned = 'True' and DataCollectionVisit = '%s'" %visit) - cursor.execute("select distinct CrystalName from collectionTable where DataCollectionVisit = '%s'" %visit) - samples = cursor.fetchall() - for sample in samples: - if str(sample[0]) not in xtalList: - xtalList.append(str(sample[0])) - return xtalList - - def autoprocessing_result_user_assigned(self,sample): - userassigned = False - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select DataProcessingAutoAssigned from mainTable where CrystalName = '%s'" %sample) - outcome = cursor.fetchall() - try: - if 'false' in str(outcome[0]).lower() or str(outcome[0]).encode('ascii', 'ignore') == '': - userassigned = True # a bit counterintuitive, but here we ask about userassigned - # whereas DB records autoassigned - except IndexError: - pass # this is the case when sample is encountered the first time - # and not yet in mainTable - - return userassigned - - - def all_results_of_xtals_collected_during_visit_as_dict(self,visitID): - # first get all collected xtals as list - collectedXtals = self.collected_xtals_during_visit(visitID) - xtalDict = {} - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - for xtal in sorted(collectedXtals): - if xtal not in xtalDict: - xtalDict[xtal] = [] - sqlite = ("select DataCollectionVisit," - " DataCollectionRun," - " DataProcessingProgram," - " DataCollectionDate," - " DataProcessingResolutionHigh," - " DataProcessingRmergeLow," - " DataCollectionCrystalImage1," - " DataCollectionCrystalImage2," - " DataCollectionCrystalImage3," - " DataCollectionCrystalImage4 " - "from collectionTable " - "where CrystalName = '%s'" % xtal) -# print sqlite - cursor.execute(sqlite) - sq = cursor.fetchall() -# print sq - for s in sq: -# print s - t=[str(s[0]),str(s[1]),str(s[2]),str(s[3]),str(s[4]),str(s[5]),str(s[6]),str(s[7]),str(s[8]),str(s[9])] - inDict = False - for entry in xtalDict[xtal]: - if t[0] == entry[0] and t[1] == entry[1] and t[2] == entry[2]: - inDict = True - break - if not inDict: - xtalDict[xtal].append(t) - return xtalDict - - def all_autoprocessing_results_for_xtal_as_dict(self,xtal): - dbList = [] - header=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select * from collectionTable where CrystalName='{0!s}';".format(xtal)) - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - for result in data: - db_dict = {} - for n,item in enumerate(result): - db_dict[header[n]]=str(item) - dbList.append(db_dict) - return dbList - - def get_db_list_for_sample_in_panddaTable(self,xtal): - dbList = [] - header=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select * from panddaTable where CrystalName='{0!s}';".format(xtal)) - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - for result in data: - db_dict = {} - for n,item in enumerate(result): - db_dict[header[n]]=str(item) - dbList.append(db_dict) - return dbList - - def get_db_dict_for_visit_run_autoproc(self,xtal,visit,run,autoproc): - db_dict = {} - header=[] - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - sqlite = ( 'select * ' - 'from collectionTable ' - "where CrystalName ='%s' and" %xtal + - " DataCollectionVisit = '%s' and" %visit + - " DataCollectionRun = '%s' and" %run + - " DataProcessingProgram = '%s'" %autoproc ) - cursor.execute(sqlite) - for column in cursor.description: - header.append(column[0]) - data = cursor.fetchall() - for n, item in enumerate(data[0]): - db_dict[header[n]] = str(item) - return db_dict - - def xtals_collected_during_visit_as_dict(self,visitID): - # first get all collected xtals as list - if isinstance(visitID,list): # for Agamemnon data structure - collectedXtals = [] - for visit in visitID: - x = self.collected_xtals_during_visit(visit) - for e in x: - collectedXtals.append(e) - else: - collectedXtals = self.collected_xtals_during_visit(visitID) - xtalDict = {} - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - for xtal in sorted(collectedXtals): - db_dict = self.get_db_dict_for_sample(xtal) - xtalDict[xtal] = db_dict - return xtalDict - - - - def getCrystalImageDict(self,visit,xtalList): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - imageDict = {} - for xtal in xtalList: - sqlite = ( "select CrystalName," - " min(DataCollectionDate)," - " DataCollectionCrystalImage1," - " DataCollectionCrystalImage2," - " DataCollectionCrystalImage3," - " DataCollectionCrystalImage4 " - "from collectionTable " - "where DataCollectionVisit = '%s'" %visit+ - " and CrystalName = '%s'" % xtal ) - cursor.execute(sqlite) - img = cursor.fetchall() - imageDict[xtal]=[str(img[1]),str(img[2]),str(img[3]),str(img[4])] - return imageDict - - def samples_for_html_summary(self): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select CrystalName from mainTable where RefinementOutcome like '4%' or " - "RefinementOutcome like '5%' or " - "RefinementOutcome like '6%' order by CrystalName ASC") - xtalList=[] - samples = cursor.fetchall() - for sample in samples: - if str(sample[0]) not in xtalList: - xtalList.append(str(sample[0])) - return xtalList - - def get_event_map_for_ligand(self,xtal,ligChain,ligNumber,ligName): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - - sql = ( - 'select ' - ' PANDDA_site_event_map ' - 'from ' - ' panddaTable ' - 'where ' - " CrystalName = '%s' and " %xtal + - " PANDDA_site_ligand_chain='%s' and " %ligChain + - " PANDDA_site_ligand_sequence_number='%s' and " %ligNumber + - " PANDDA_site_ligand_resname='%s'" %ligName - ) - - cursor.execute(sql) - - eventMap = '' - maps = cursor.fetchall() - for map in maps: - eventMap = map[0] - - return eventMap - - def get_ligand_confidence_for_ligand(self,xtal,ligChain,ligNumber,ligName): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - - sql = ( - 'select ' - ' PANDDA_site_confidence ' - 'from ' - ' panddaTable ' - 'where ' - " CrystalName = '%s' and " %xtal + - " PANDDA_site_ligand_chain='%s' and " %ligChain + - " PANDDA_site_ligand_sequence_number='%s' and " %ligNumber + - " PANDDA_site_ligand_resname='%s'" %ligName - ) - - cursor.execute(sql) - - ligConfidence = 'not assigned' - ligs = cursor.fetchall() - for lig in ligs: - ligConfidence = lig[0] - - return ligConfidence - - def get_labels_from_db(self): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute('select Label from labelTable') - labels = cursor.fetchall() - labelList = [] - for l in labels: - labelList.append(l[0]) - return labelList - - def get_label_info_from_db(self): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute('select Label,Description from labelTable') - labels = cursor.fetchall() - labelList = [] - for l in labels: - labelList.append([str(l[0]),str(l[1])]) - return labelList - - def get_label_of_sample(self,xtalID): - connect=sqlite3.connect(self.data_source_file) # creates sqlite file if non existent - cursor = connect.cursor() - cursor.execute("select label from mainTable where CrystalName is '%s'" %xtalID) - label = None - lab = cursor.fetchall() - for l in lab: - label = l[0] - break - return label diff --git a/lib/XChemDeposit.py b/lib/XChemDeposit.py deleted file mode 100755 index e5c5fff9..00000000 --- a/lib/XChemDeposit.py +++ /dev/null @@ -1,1401 +0,0 @@ -# last edited: 16/05/2017, 15:00 - -import sys -import fileinput -import os -import glob - -from PyQt4 import QtGui, QtCore, QtWebKit - -from lxml import etree - -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -import XChemLog -import XChemDB -import XChemToolTips -import XChemMain -from XChemUtils import pdbtools -from XChemUtils import mtztools -from XChemUtils import smilestools - - -def create_SF_mmcif(outDir,mtzList): - print 'hallo' - -def get_protein_sequence(database,xtalID): - print 'hallo' - -def check_depositDict(depositDict): - # check depositDict - for entry in depositDict: - if 'middle_name' in depositDict[entry]: - continue - elif 'State_or_Province' in depositDict[entry]: - continue - elif depositDict[entry] == '': - print 'ERROR' - -def update_title(depositDict): - - print 'hallo' - -def create_data_template_text(): - - data_template_text=data_template(depositDict,sequence) - -def create_Model_mmcif(outDir,pdbList): - print 'hallo' - -#def update_file_locations_of_apo_structuresin_DB(database,projectDir,xce_logfile): -# Logfile=XChemLog.updateLog(xce_logfile) -# Logfile.insert('updating file information for apo structures') -# db=XChemDB.data_source(database) -# apo=db.execute_statement("select CrystalName from depositTable where StructureType is 'apo';") -# for item in apo: -# xtal=str(item[0]) -# db_dict={} -# db_dict['label']=xtal+'-apo' -# db_dict['description']='apo structure for pandda.analyse' -# if os.path.isfile(os.path.join(projectDir,xtal,'dimple.pdb')): -# db_dict['PDB_file']=os.path.realpath(os.path.join(projectDir,xtal,'dimple.pdb')) -# if os.path.isfile(os.path.join(projectDir,xtal,'dimple.mtz')): -# db_dict['MTZ_file']=os.path.realpath(os.path.join(projectDir,xtal,'dimple.mtz')) -# Logfile.insert('updating depositTable for apo structure '+xtal) -# db.update_depositTable(xtal,'apo',db_dict) - - - -class templates: - - def data_template_cif(self,depositDict): - - taxonomy_dict=XChemMain.NCBI_taxonomy_ID() - for key in taxonomy_dict: - if taxonomy_dict[key]==depositDict['Source_organism_scientific_name']: - pdbx_gene_src_ncbi_taxonomy_id=key - if taxonomy_dict[key]==depositDict['Expression_system_scientific_name']: - pdbx_host_org_ncbi_taxonomy_id=key - -# structure_author_name='' -# for name in depositDict['structure_author_name'].split(';'): -# structure_author_name+='\n' %name - - audit_author_name='' - # one name must be within quotation, last name and first initial must be separated by comma and space - for name in depositDict['structure_author_name'].split(';'): - if name.replace(' ','') == '': - continue - if name[name.find(',')+1:name.find(',')+2] != ' ': - name=name.replace(',',', ') - audit_author_name+="'{0!s}'\n".format(name) - - primary_citation_author_name='' - # one name must be within quotation, last name and first initial must be separated by comma and space - for name in depositDict['primary_citation_author_name'].split(';'): - if name.replace(' ','') == '': - continue - if name[name.find(',')+1:name.find(',')+2] != ' ': - name=name.replace(',',', ') - primary_citation_author_name+="primary '{0!s}'\n".format(name) - - molecule_one_letter_sequence=';' - counter=1 - for aa in depositDict['molecule_one_letter_sequence']: - if counter < 70: - molecule_one_letter_sequence+=aa - if counter == 70: - molecule_one_letter_sequence+='\n'+aa - counter = 0 - counter+=1 - - if depositDict['molecule_name_two'].replace(' ','') == '' or depositDict['molecule_name_two'].replace(' ','').lower() == 'none': - entity = ( - 'loop_\n' - '_entity.id\n' - '_entity.type\n' - '_entity.src_method\n' - '_entity.pdbx_description\n' - '_entity.pdbx_mutation\n' - '1 polymer man "%s" %s\n' % (depositDict['Source_organism_gene'], depositDict['fragment_name_one_specific_mutation']) + - '#\n' - 'loop_\n' - '_entity_poly.entity_id\n' - '_entity_poly.type\n' - '_entity_poly.pdbx_seq_one_letter_code\n' - '_entity_poly.pdbx_strand_id\n' - '_entity_poly.pdbx_seq_db_id\n' - '_entity_poly.pdbx_seq_db_name\n' - '1 "polypeptide(L)"\n' - + molecule_one_letter_sequence + '\n' - ';\n' - '%s %s UNP\n' %(depositDict['protein_chains'],depositDict['molecule_one_letter_sequence_uniprot_id'])+ - '#\n' - 'loop_\n' - '_entity_src_gen.entity_id\n' - '_entity_src_gen.gene_src_strain\n' - '_entity_src_gen.pdbx_gene_src_scientific_name\n' - '_entity_src_gen.pdbx_gene_src_ncbi_taxonomy_id\n' - '_entity_src_gen.pdbx_host_org_scientific_name\n' - '_entity_src_gen.pdbx_host_org_ncbi_taxonomy_id\n' - '1 ? "%s" %s "%s" %s\n' % (depositDict['Source_organism_scientific_name'], pdbx_gene_src_ncbi_taxonomy_id,depositDict['Expression_system_scientific_name'], pdbx_host_org_ncbi_taxonomy_id) + - '#\n' - ) - else: - molecule_two_letter_sequence=';' - counter=1 - for aa in depositDict['molecule_two_letter_sequence']: - if counter < 70: - molecule_two_letter_sequence+=aa - if counter == 70: - molecule_two_letter_sequence+='\n'+aa - counter = 0 - counter+=1 - - entity = ( - 'loop_\n' - '_entity.id\n' - '_entity.type\n' - '_entity.src_method\n' - '_entity.pdbx_description\n' - '_entity.pdbx_mutation\n' - '1 polymer man "%s" %s\n' % (depositDict['Source_organism_gene'], depositDict['fragment_name_one_specific_mutation']) + - '2 polymer man "%s" %s\n' % (depositDict['Source_organism_gene_two'], depositDict['fragment_name_two_specific_mutation']) + - '#\n' - 'loop_\n' - '_entity_poly.entity_id\n' - '_entity_poly.type\n' - '_entity_poly.pdbx_seq_one_letter_code\n' - '_entity_poly.pdbx_strand_id\n' - '_entity_poly.pdbx_seq_db_id\n' - '_entity_poly.pdbx_seq_db_name\n' - '1 "polypeptide(L)"\n' - + molecule_one_letter_sequence + '\n' - ';\n' - '%s %s UNP\n' %(depositDict['molecule_chain_one'],depositDict['molecule_one_letter_sequence_uniprot_id'])+ -# ';\n' - '2 "polypeptide(L)"\n' - + molecule_two_letter_sequence + '\n' - ';\n' - '%s %s UNP\n' %(depositDict['molecule_chain_two'],depositDict['molecule_two_letter_sequence_uniprot_id'])+ - '#\n' - 'loop_\n' - '_entity_src_gen.entity_id\n' - '_entity_src_gen.gene_src_strain\n' - '_entity_src_gen.pdbx_gene_src_scientific_name\n' - '_entity_src_gen.pdbx_gene_src_ncbi_taxonomy_id\n' - '_entity_src_gen.pdbx_host_org_scientific_name\n' - '_entity_src_gen.pdbx_host_org_ncbi_taxonomy_id\n' - '1 ? "%s" %s "%s" %s\n' % (depositDict['Source_organism_scientific_name'], pdbx_gene_src_ncbi_taxonomy_id,depositDict['Expression_system_scientific_name'], pdbx_host_org_ncbi_taxonomy_id) + - '2 ? "%s" %s "%s" %s\n' % (depositDict['Source_organism_scientific_name'], pdbx_gene_src_ncbi_taxonomy_id,depositDict['Expression_system_scientific_name'], pdbx_host_org_ncbi_taxonomy_id) + - '#\n' - ) - - - data_template_cif = ( - 'data_UNNAMED\n' - '#\n' - '_pdbx_database_status.entry_id UNNAMED\n' - "_pdbx_database_status.dep_release_code_coordinates '%s'\n" %depositDict['Release_status_for_coordinates']+ - "_pdbx_database_status.dep_release_code_sequence '{0!s}'\n".format(depositDict['Release_status_for_sequence'])+ - '#\n' - '_pdbx_deposit_group.group_id UNNAMED\n' - '_pdbx_deposit_group.group_description "%s"\n' %depositDict['group_description']+ - '_pdbx_deposit_group.group_title "{0!s}"\n'.format(depositDict['group_title'])+ - '_pdbx_deposit_group.group_type "{0!s}"\n'.format(depositDict['group_type'])+ - '#\n' - '_exptl_crystal_grow.crystal_id 1\n' - "_exptl_crystal_grow.method '%s'\n" %depositDict['crystallization_method']+ - '_exptl_crystal_grow.pH {0!s}\n'.format(depositDict['crystallization_pH'])+ - '_exptl_crystal_grow.temp {0!s}\n'.format(depositDict['crystallization_temperature'])+ - '_exptl_crystal_grow.pdbx_details "{0!s}"\n'.format(depositDict['crystallization_details'])+ - '#\n' - '_diffrn.id 1\n' - '_diffrn.ambient_temp %s\n' %depositDict['data_collection_temperature']+ - '_diffrn.crystal_id 1\n' - '#\n' - '_diffrn_source.diffrn_id 1\n' - '_diffrn_source.source %s\n' %depositDict['radiation_source']+ - '_diffrn_source.type "{0!s}"\n'.format(depositDict['radiation_source_type'])+ - '_diffrn_source.pdbx_wavelength_list {0!s}\n'.format(depositDict['radiation_wavelengths'])+ - '#\n' - '_diffrn_detector.detector %s\n' %depositDict['radiation_detector']+ - "_diffrn_detector.type '{0!s}'\n".format(depositDict['radiation_detector_type'])+ - '_diffrn_detector.pdbx_collection_date {0!s}\n'.format(depositDict['data_collection_date'])+ - '_diffrn_detector.diffrn_id 1\n' - '#\n' - '_diffrn_radiation.diffrn_id 1\n' - '_diffrn_radiation.wavelength_id 1\n' - "_diffrn_radiation.pdbx_diffrn_protocol 'SINGLE WAVELENGTH'\n" - '#\n' - '_diffrn_radiation_wavelength.id 1\n' - '_diffrn_radiation_wavelength.wavelength %s\n' %depositDict['radiation_wavelengths']+ - '#\n' - '#\n' - + entity + -# 'loop_\n' -# '_entity.id\n' -# '_entity.type\n' -# '_entity.src_method\n' -# '_entity.pdbx_description\n' -# '_entity.pdbx_mutation\n' -# '1 polymer man "%s" %s\n' %(depositDict['Source_organism_gene'],depositDict['fragment_name_one_specific_mutation'])+ -# '#\n' -# 'loop_\n' -# '_entity_poly.entity_id\n' -# '_entity_poly.type\n' -# '_entity_poly.pdbx_seq_one_letter_code\n' -# '_entity_poly.pdbx_strand_id\n' -# '_entity_poly.pdbx_seq_db_id\n' -# '_entity_poly.pdbx_seq_db_name\n' -# '1 "polypeptide(L)"\n' -# +molecule_one_letter_sequence+'\n' -# ';\n' -# '%s %s UNP\n' %(depositDict['protein_chains'],depositDict['molecule_one_letter_sequence_uniprot_id'])+ -# '#\n' -# 'loop_\n' -# '_entity_src_gen.entity_id\n' -# '_entity_src_gen.gene_src_strain\n' -# '_entity_src_gen.pdbx_gene_src_scientific_name\n' -# '_entity_src_gen.pdbx_gene_src_ncbi_taxonomy_id\n' -# '_entity_src_gen.pdbx_host_org_scientific_name\n' -# '_entity_src_gen.pdbx_host_org_ncbi_taxonomy_id\n' -# '1 ? "%s" %s "%s" %s\n' %(depositDict['Source_organism_scientific_name'],pdbx_gene_src_ncbi_taxonomy_id,depositDict['Expression_system_scientific_name'],pdbx_host_org_ncbi_taxonomy_id)+ -# '#\n' - 'loop_\n' - '_pdbx_contact_author.id \n' - "_pdbx_contact_author.address_1 \n" - '_pdbx_contact_author.address_2 \n' - '_pdbx_contact_author.city \n' - "_pdbx_contact_author.state_province \n" - '_pdbx_contact_author.postal_code \n' - '_pdbx_contact_author.email \n' - '_pdbx_contact_author.name_first \n' - '_pdbx_contact_author.name_last \n' - '_pdbx_contact_author.country \n' - '_pdbx_contact_author.phone \n' - '_pdbx_contact_author.role \n' - '_pdbx_contact_author.organization_type \n' - "1 '%s' '%s' '%s' '%s' '%s' %s %s '%s' '%s' '%s' '%s' %s\n" %(depositDict['contact_author_PI_address'],depositDict['contact_author_PI_organization_name'],depositDict['contact_author_PI_city'],depositDict['contact_author_PI_State_or_Province'],depositDict['contact_author_PI_Zip_Code'],depositDict['contact_author_PI_email'],depositDict['contact_author_PI_first_name'],depositDict['contact_author_PI_last_name'],depositDict['contact_author_PI_Country'],depositDict['contact_author_PI_phone_number'],depositDict['contact_author_PI_role'],depositDict['contact_author_PI_organization_type'])+ - "2 '{0!s}' '{1!s}' '{2!s}' '{3!s}' '{4!s}' {5!s} {6!s} '{7!s}' '{8!s}' '{9!s}' '{10!s}' {11!s}\n".format(depositDict['contact_author_address'], depositDict['contact_author_organization_name'], depositDict['contact_author_city'], depositDict['contact_author_State_or_Province'], depositDict['contact_author_Zip_Code'].replace(' ',''), depositDict['contact_author_email'], depositDict['contact_author_first_name'], depositDict['contact_author_last_name'], depositDict['contact_author_Country'], depositDict['contact_author_phone_number'], depositDict['contact_author_role'], depositDict['contact_author_organization_type'])+ - '#\n' - 'loop_\n' - '_audit_author.name\n' - +audit_author_name+ -# "'%s, %s.'\n" %(depositDict['contact_author_last_name'],depositDict['contact_author_first_name'][0])+ - '#\n' - '_citation.id primary\n' - "_citation.title '%s'\n" %depositDict['group_title']+ - "_citation.journal_abbrev 'To Be Published'\n" - '#\n' - 'loop_\n' - '_citation_author.citation_id\n' - '_citation_author.name\n' - +primary_citation_author_name+ -# "primary 'Krojer, T.'\n" -# "primary 'Von Delft, F.'\n" - '#\n' - '_struct.entry_id UNNAMED\n' - '_struct.title\n' - ';%s\n' %depositDict['title']+ - ';\n' - '#\n' - '_struct_keywords.entry_id UNNAMED\n' - '_struct_keywords.text "%s"\n' %depositDict['structure_keywords']+ - '#\n' - '_pdbx_struct_assembly_depositor_info.id 1\n' - "_pdbx_struct_assembly_depositor_info.method_details PISA\n" - '_pdbx_struct_assembly_depositor_info.oligomeric_count %s\n' %depositDict['biological_assembly_chain_number']+ - '#\n' - '#\n' - ) - - return data_template_cif - - - -class update_depositTable(QtCore.QThread): - def __init__(self,deposit_dict,database,xce_logfile): - QtCore.QThread.__init__(self) - self.deposit_dict=deposit_dict - self.database=database - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(database) - - def run(self): - self.Logfile.insert('all entries in the depositTable will be updated with the following values:') - for key in self.deposit_dict: - self.Logfile.insert(key+': '+self.deposit_dict[key]) - dbEntries=self.db.execute_statement("select CrystalName,StructureType from depositTable;") - for item in dbEntries: - xtal=str(item[0]) - type=str(item[1]) - db_dict=self.deposit_dict # need to do this because individual fields might need updating for some xtals - - # try to get information about the diffraction experiment - try: - diffractionExperiment=self.db.execute_statement("select DataCollectionBeamline,DataCollectionDate from mainTable where CrystalName is '{0!s}'".format(xtal)) - beamline=str(diffractionExperiment[0][0]) - date=str(diffractionExperiment[0][1]) - except (UnboundLocalError,IndexError): - self.Logfile.warning('%s: cannot find details about diffraction experiment in mainTable' %xtal) - beamline = db_dict['radiation_source'] - date = db_dict['data_collection_date'] - self.Logfile.warning('%s: using values provided in depositTable for beamline and data collection date' %xtal) - if beamline.lower() != 'none': - db_dict=self.tweak_deposit_dict(xtal,db_dict) - if date.lower() != 'none': - db_dict['data_collection_date']=date.split()[0] - - self.Logfile.insert('updating depositTable for '+xtal+' @ '+type) - self.db.update_depositTable(xtal,type,db_dict) - self.Logfile.insert('Note: use DBbrowser to edit individual entries') - - def tweak_deposit_dict(self,xtal,db_dict): - dls_beamlines=['i02','i03','i04','i04-1','i23','i24'] - dls_beamline_dict = { 'i02': ['DIAMOND BEAMLINE I02', 'DECTRIS PILATUS 6M'], - 'i03': ['DIAMOND BEAMLINE I03', 'DECTRIS PILATUS 6M'], - 'i04': ['DIAMOND BEAMLINE I04', 'DECTRIS PILATUS 6M'], - 'i04-1': ['DIAMOND BEAMLINE I04-1', 'DECTRIS PILATUS 6M'], - 'i23': ['DIAMOND BEAMLINE I23', 'DECTRIS PILATUS 12M'], - 'i24': ['DIAMOND BEAMLINE I24', 'DECTRIS PILATUS 6M'] , } - - if db_dict['radiation_source_type'] in dls_beamlines: - db_dict['radiation_source_type']= dls_beamline_dict[db_dict['radiation_source_type']][0] - db_dict['radiation_detector_type']= dls_beamline_dict[db_dict['radiation_source_type']][1] - db_dict['radiation_detector']= 'PIXEL' - db_dict['radiation_source']= 'SYNCHROTRON' - - return db_dict - - - - -class prepare_mmcif_files_for_deposition(QtCore.QThread): - - def __init__(self,database,xce_logfile,overwrite_existing_mmcif,projectDir,ground_state,ignore_event_map): - QtCore.QThread.__init__(self) - self.database=database - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(database) - self.overwrite_existing_mmcif=overwrite_existing_mmcif - self.projectDir=projectDir - self.data_template_dict={} - - self.errorList = [] - self.eventList = [] - self.db_dict = None - self.data_template_dict = None - self.zenodo_dict = None - self.pdb = None - self.mtz = None - - self.ground_state = False - self.ground_state_pdb = '' - self.ground_state_mean_mtz = '' - self.panddaDir = '' - self.ignore_event_map = ignore_event_map - if ground_state: - self.ground_state = True - self.ground_state_pdb = ground_state[0] - self.ground_state_mean_mtz = ground_state[1] - self.panddaDir = ground_state[2] - self.projectDir = self.panddaDir - self.pdb = pdbtools(self.ground_state_pdb) - self.mtz = mtztools(self.ground_state_mean_mtz) - - def run(self): - - self.Logfile.insert('======= preparing mmcif files for wwPDB deposition =======') - self.Logfile.insert('checking DB for structures to deposit...') - if self.ground_state: - toDeposit = self.db.execute_statement("select CrystalName from depositTable where DimplePANDDApath = '%s';" %self.panddaDir) - else: - toDeposit = self.db.execute_statement("select CrystalName from mainTable where RefinementOutcome like '5%';") - self.Logfile.insert('found ' + str(len(toDeposit)) + ' samples ready for deposition') - - progress_step=1 - if len(toDeposit) != 0: - progress_step=100/float(len(toDeposit)) - else: - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - for item in sorted(toDeposit): - xtal=str(item[0]) - if self.ground_state: - os.chdir(self.projectDir) # projectDir == referenceDir in this case - else: - os.chdir(os.path.join(self.projectDir, xtal)) - self.Logfile.insert('%s: ----- preparing files for deposition -----' %xtal) - - if self.ground_state: - if not self.data_template_dict_exists(xtal): - continue - - if not self.zenodo_dict_exists(xtal): - continue - - if not self.save_data_template_dict(xtal): - continue - - if not self.create_model_mmcif(xtal): - continue - - if not self.create_sf_mmcif(xtal): - continue - - if not self.apo_mmcif_exists(): - continue - - if not self.add_apo_sf_mmcif_to_ground_state_mmcif(): - continue - - if not self.add_data_increment_to_apo_mmcif(): - continue - - else: - if not self.mmcif_files_can_be_replaced(xtal): - continue - - if not self.data_template_dict_exists(xtal): - continue - - if not self.db_dict_exists(xtal): - continue - - if not self.zenodo_dict_exists(xtal): - continue - - if not self.refine_bound_exists(xtal): - continue - - if not self.refine_mtz_exists(xtal): - continue - - if not self.mtzFree_exists(xtal): - continue - - if not self.aimless_logfile_exists(xtal): - continue - - if not self.ligand_in_pdb_file(xtal): - continue - - if not self.eventMTZ_exists((xtal)): - continue - - if not self.find_matching_event_map(xtal): - continue - - if not self.save_data_template_dict(xtal): - continue - - if not self.create_model_mmcif(xtal): - continue - - if not self.create_sf_mmcif(xtal): - continue - - if not self.event_maps_exist_in_sf_mmcif(xtal): - continue - - self.make_table_one(xtal) - - - self.print_errorlist() - self.Logfile.insert('======= finished preparing mmcif files for wwPDB deposition =======') - - def ground_state_mmcif_exists(self): - mmcifStatus = False - for dirs in glob.glob(os.path.join(self.panddaDir, 'processed_datasets', '*')): - xtal = dirs[dirs.rfind('/') + 1:] - if os.path.isfile(os.path.join(dirs, xtal + '_sf.mmcif')): - self.Logfile.insert('%s: found mmcif file for apo structure' %xtal) - mmcifStatus = True - - return mmcifStatus - - def data_template_dict_exists(self,xtal): - dictStatus = False - self.data_template_dict = None - self.Logfile.insert('%s: reading information from depositTable for sample' % xtal) - self.data_template_dict = self.db.get_deposit_dict_for_sample(xtal) - if self.data_template_dict == {}: - self.Logfile.error('%s: cannot find data_template dictionary in depositTable; moving to next dataset...' %xtal) - self.add_to_errorList(xtal) - else: - self.Logfile.insert('%s: found data_template dictionary in depositTable' % xtal) - dictStatus = True - return dictStatus - - def update_beamline_info_data_template_dict(self,xtal): - dls_beamlines=['i02','i03','i04','i04-1','i23','i24'] - dls_beamline_dict = { 'i02': ['DIAMOND BEAMLINE I02', 'DECTRIS PILATUS 6M'], - 'i03': ['DIAMOND BEAMLINE I03', 'DECTRIS PILATUS 6M'], - 'i04': ['DIAMOND BEAMLINE I04', 'DECTRIS PILATUS 6M'], - 'i04-1': ['DIAMOND BEAMLINE I04-1', 'DECTRIS PILATUS 6M'], - 'i23': ['DIAMOND BEAMLINE I23', 'DECTRIS PILATUS 12M'], - 'i24': ['DIAMOND BEAMLINE I24', 'DECTRIS PILATUS 6M'] , } - - if self.db_dict['DataCollectionBeamline'] in dls_beamlines: - self.data_template_dict['radiation_source_type']= dls_beamline_dict[self.db_dict['DataCollectionBeamline']][0] - self.data_template_dict['radiation_detector_type']= dls_beamline_dict[self.db_dict['DataCollectionBeamline']][1] - self.data_template_dict['radiation_detector']= 'PIXEL' - self.data_template_dict['radiation_source']= 'SYNCHROTRON' - self.Logfile.insert(('%s: setting data collection beamline to %s' %(xtal,self.data_template_dict['radiation_source_type']))) - - - def db_dict_exists(self,xtal): - dictStatus = False - self.db_dict = None - self.Logfile.insert('%s: reading information from mainTable for sample' % xtal) - self.db_dict = self.db.get_db_dict_for_sample(xtal) - if self.db_dict == {}: - self.Logfile.error('%s: cannot find db_dict dictionary in mainTable; moving to next dataset...' %xtal) - self.add_to_errorList(xtal) - else: - self.Logfile.insert('%s: found db_dict dictionary in mainTable' % xtal) - self.update_beamline_info_data_template_dict(xtal) - dictStatus = True - return dictStatus - - def zenodo_dict_exists(self,xtal): - dictStatus = False - self.zenodo_dict = None - if self.ground_state: - self.zenodo_dict = self.db.get_zenodo_dict_for_pandda_analysis(self.panddaDir) - else: - self.Logfile.insert('%s: reading information from zenodoTable for pandda run: %s' % (xtal, self.db_dict['DimplePANDDApath'])) - self.zenodo_dict = self.db.get_zenodo_dict_for_pandda_analysis(self.db_dict['DimplePANDDApath']) - if self.zenodo_dict == {}: - dictStatus = True - self.zenodo_dict['ZenodoDOI'] = '' - self.Logfile.warning('%s: cannot find information about zenodo deposition in zenodoTable!!!' %xtal) -# self.Logfile.error('%s: cannot find information about zenodo deposition in zenodoTable; moving to next dataset...' %xtal) -# self.add_to_errorList(xtal) - else: - self.Logfile.insert('%s: found zenodo_dict dictionary in zenodoTable' % xtal) - dictStatus = True - return dictStatus - - - def mmcif_files_can_be_replaced(self,xtal): - status = True - if self.overwrite_existing_mmcif: - self.Logfile.insert('%s: removing existing mmcif files as chosen by user' %xtal) - self.db.execute_statement("update depositTable set mmCIF_model_file='',mmCIF_SF_file='' where CrystalName is '{0!s}'".format(xtal)) - for mmcif in glob.glob('*.mmcif'): - self.Logfile.warning('%s: removing %s' %(xtal,mmcif)) - os.system('/bin/rm ' + mmcif) - else: - for mmcif in glob.glob('*.mmcif'): - self.Logfile.warning('%s: %s exists; skipping...' %(xtal,mmcif)) - status = False - return status - - - - def refine_bound_exists(self,xtal): - self.pdb = None - self.Logfile.insert('%s: checking if refine.split.bound-state.pdb exists' %xtal) - fileStatus = False - if os.path.isfile('refine.split.bound-state.pdb'): - self.Logfile.insert('%s: found refine.split.bound-state.pdb' %xtal) - self.pdb = pdbtools('refine.split.bound-state.pdb') - fileStatus = True - else: - self.Logfile.error('%s: cannot find refine.split.bound-state.pdb; moving to next dataset...' %xtal) - self.add_to_errorList(xtal) - return fileStatus - - def refine_mtz_exists(self,xtal): - self.mtz = None - self.Logfile.insert('%s: checking if refine.mtz exists' %xtal) - fileStatus = False - if os.path.isfile('refine.mtz'): - self.Logfile.insert('%s: found refine.mtz' %xtal) - self.mtz = mtztools('refine.mtz') - fileStatus = True - else: - self.Logfile.error('%s: cannot find refine.mtz; moving to next dataset...' %xtal) - self.add_to_errorList(xtal) - return fileStatus - - def aimless_logfile_exists(self,xtal): - self.Logfile.insert('%s: checking if aimless logfile, i.e. %s.log, exists' %(xtal,xtal)) - fileStatus = False - if os.path.isfile('%s.log' %xtal): - self.Logfile.insert('%s: found %s.log' %(xtal,xtal)) - fileStatus = True - else: - self.Logfile.error('%s: cannot find %s.log; moving to next dataset...' %(xtal,xtal)) - self.add_to_errorList(xtal) - return fileStatus - - - def mtzFree_exists(self,xtal): - self.Logfile.insert('%s: checking if %s.free.mtz exists' %(xtal,xtal)) - fileStatus = False - if os.path.isfile('%s.free.mtz' %xtal): - self.Logfile.insert('%s: found %s.free.mtz' %(xtal,xtal)) - fileStatus = True - else: - self.Logfile.error('%s: cannot find %s.free.mtz; moving to next dataset...' %(xtal,xtal)) - self.add_to_errorList(xtal) - return fileStatus - - - def ligand_in_pdb_file(self,xtal): - self.Logfile.insert('%s: checking if refine.split.bound-state.pdb contains ligands of type LIG' %xtal) - ligandStatus = False - ligList = pdbtools('refine.split.bound-state.pdb').get_residues_with_resname('LIG') - if ligList is []: - self.Logfile.error('%s: refine.split.bound-state.pdb does not contain any modelled ligands of type LIG' %xtal) - self.add_to_errorList(xtal) - else: - self.Logfile.insert(xtal + ': found ' + str(len(ligList)) + ' ligands of type LIG') - ligandStatus = True - return ligandStatus - - def eventMTZ_exists(self,xtal): - self.Logfile.insert('%s: checking if mtz of event maps exists' %xtal) - eventMTZlist = [] - eventMTZexists = False - if os.path.isfile('no_pandda_analysis_performed'): - self.Logfile.warning('%s: found empty file named "no_pandda_analysis_performed" which suggests we will ignore event maps for this sample' %xtal) - eventMTZexists = True - elif self.ignore_event_map: - self.Logfile.warning('%s: user selected to not include event map in SF mmcif file' %xtal) - eventMTZexists = True - else: - for mtz in glob.glob('*event*.native*P1.mtz'): - eventMTZlist.append(mtz[mtz.rfind('/')+1:]) - if eventMTZlist is []: - self.Logfile.error('%s: MTZ files of event maps do not exists! Go to PANDDA tab and run "Event Map -> SF"' %xtal) - self.add_to_errorList(xtal) - else: - self.Logfile.insert(xtal + ': found ' + str(len(eventMTZlist)) + ' MTZ files of event maps') - eventMTZexists = True - return eventMTZexists - - - def find_matching_event_map(self,xtal): - self.eventList = [] - self.Logfile.insert('%s: trying to find fitting event maps for modelled ligands' %xtal) - ligList = self.pdb.save_residues_with_resname(os.path.join(self.projectDir,xtal), 'LIG') - foundMatchingMap = None - if os.path.isfile('no_pandda_analysis_performed') or self.ignore_event_map: - self.Logfile.warning('%s: found empty file named "no_pandda_analysis_performed" which suggests we will ignore event maps for this sample' %xtal) - foundMatchingMap = True - ligList = [] - for lig in sorted(ligList): - ligID = lig.replace('.pdb','') -# if os.path.isfile('no_pandda_analysis_performed'): -# self.Logfile.warning('%s: no pandda analysis performed; skipping this step...' %xtal) -# foundMatchingMap = True -# break - ligCC = [] - for mtz in sorted(glob.glob('*event*.native*P1.mtz')): - self.get_lig_cc(xtal, mtz, lig) - cc = self.check_lig_cc(mtz.replace('.mtz', '_CC'+ligID+'.log')) - self.Logfile.insert('%s: %s -> CC = %s for %s' %(xtal,ligID,cc,mtz)) - try: - ligCC.append([mtz,float(cc)]) - except ValueError: - ligCC.append([mtz, 0.00]) - highestCC = max(ligCC, key=lambda x: x[0])[1] - if highestCC == 0.00 or ligCC is []: - self.Logfile.error('%s: best CC of ligand %s for any event map is 0!' %(xtal,lig)) - self.add_to_errorList(xtal) - foundMatchingMap = False - else: - self.Logfile.insert('%s: selected event map -> CC(%s) = %s for %s' %(xtal,lig,highestCC,mtz[mtz.rfind('/')+1:])) - if mtz not in self.eventList: - self.eventList.append(mtz) - if foundMatchingMap is None: - foundMatchingMap = True - return foundMatchingMap - - - def get_lig_cc(self, xtal, mtz, lig): - ligID = lig.replace('.pdb','') - self.Logfile.insert('%s: calculating CC for %s in %s' %(xtal,lig,mtz)) - if os.path.isfile(mtz.replace('.mtz', '_CC'+ligID+'.log')): - self.Logfile.warning('logfile of CC analysis exists; skipping...') - return - cmd = ( 'module load phenix\n' - 'phenix.get_cc_mtz_pdb %s %s > %s' % (mtz, lig, mtz.replace('.mtz', '_CC'+ligID+'.log')) ) - os.system(cmd) - - def check_lig_cc(self,log): - cc = 'n/a' - if os.path.isfile(log): - for line in open(log): - if line.startswith('local'): - cc = line.split()[len(line.split()) - 1] - else: - self.Logfile.error('logfile does not exist: %s' %log) - return cc - - - def add_to_errorList(self,xtal): - if xtal not in self.errorList: - self.errorList.append(xtal) - - def print_errorlist(self): - if not self.errorList: - self.Logfile.insert('XCE did not detect any problems during mmcif file preparation. ' - 'It is however recommended to check the logfile.') - else: - self.Logfile.warning('The following samples had problems during mmcif creation. ' - 'Please check the logfile for details!') - for xtal in self.errorList: - self.Logfile.error(xtal) - - - def save_data_template_dict(self,xtal): - # check if file exists - noError = True - self.Logfile.insert('%s: preparing data_template.cif file' %xtal) - if self.overwrite_existing_mmcif: - self.data_template_dict['radiation_wavelengths'] = self.mtz.get_wavelength() - self.Logfile.insert('%s: experimental wavelength according to %s is %s' %(xtal,self.mtz,self.data_template_dict['radiation_wavelengths'])) - if self.ground_state: - os.chdir(self.projectDir) -# self.data_template_dict['radiation_wavelengths'] = '1.000' - self.data_template_dict['group_type'] = 'ground state' - self.data_template_dict['group_title'] = 'PanDDA analysis group deposition of ground-state model' - self.data_template_dict['group_description'] = self.data_template_dict['group_description'].replace('$ProteinName', - self.data_template_dict[ - 'Source_organism_gene']) - self.data_template_dict['title'] = self.data_template_dict['structure_title_apo'].replace('$ProteinName', - self.data_template_dict[ - 'Source_organism_gene']) - else: - os.chdir(os.path.join(self.projectDir, xtal)) - # edit wavelength -# self.data_template_dict['radiation_wavelengths'] = self.mtz.get_wavelength() - - title = self.data_template_dict['structure_title'].replace('$ProteinName', self.data_template_dict[ - 'Source_organism_gene']).replace('$CompoundName', self.db_dict['CompoundCode']) - - self.data_template_dict['group_type'] = 'changed state' - - - # edit title - self.data_template_dict['group_title'] = self.data_template_dict['group_deposition_title'].replace('$ProteinName', - self.data_template_dict[ - 'Source_organism_gene']).replace( - '$CompoundName', self.db_dict['CompoundCode']) - -# self.data_template_dict[ -# 'group_title'] = 'PanDDA analysis group deposition of models with modelled events (e.g. bound ligands)' - self.data_template_dict['group_description'] = self.data_template_dict['group_description'].replace('$ProteinName', - self.data_template_dict[ - 'Source_organism_gene']) - self.data_template_dict['title'] = self.data_template_dict['group_title'] + ' -- ' + title - - if ('$ProteinName' or '$CompoundName') in self.data_template_dict['title']: - self.Logfile.error('%s: data_template - title not correctly formatted') - self.add_to_errorList(xtal) - noError = False - - # mutations - mutations = self.data_template_dict['fragment_name_one_specific_mutation'] - if mutations.lower().replace(' ', '').replace('none', '').replace('null', '') == '': - self.data_template_dict['fragment_name_one_specific_mutation'] = '?' - else: - self.data_template_dict['fragment_name_one_specific_mutation'] = '"' + mutations.replace(' ', '') + '"' - - # get protein chains - self.data_template_dict['protein_chains'] = '' - chains = self.pdb.GetProteinChains() - for item in chains: - self.data_template_dict['protein_chains'] += item + ',' - self.data_template_dict['protein_chains'] = self.data_template_dict['protein_chains'][:-1] - - data_template = templates().data_template_cif(self.data_template_dict) -# site_details = self.make_site_description(xtal) -# data_template += site_details - if self.ground_state: - f = open(os.path.join(self.projectDir, 'data_template.cif'), 'w') - else: - f = open(os.path.join(self.projectDir, xtal, 'data_template.cif'), 'w') - - f.write(data_template) - f.close() - - return noError - - - def create_model_mmcif(self,xtal): - fileStatus = False - if self.ground_state: - os.chdir(os.path.join(self.projectDir)) - else: - os.chdir(os.path.join(self.projectDir, xtal)) - refSoft = self.pdb.get_refinement_program() - - if os.path.isdir('/dls'): - pdb_extract_init = 'source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n' - pdb_extract_init += '/dls/science/groups/i04-1/software/pdb-extract-prod/bin/pdb_extract' - else: - pdb_extract_init = 'source ' + os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/setup.sh') + '\n' - pdb_extract_init += +os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/bin/pdb_extract') - - if self.ground_state: - Cmd = (pdb_extract_init + - ' -r {0!s}'.format(refSoft) + - ' -iPDB {0!s}'.format(self.ground_state_pdb) + - ' -e MR' - ' -s AIMLESS' - ' -iLOG {0!s}'.format(self.ground_state_pdb.replace('.pdb','.log')) + - ' -iENT data_template.cif' - ' -o {0!s}.mmcif > {1!s}.mmcif.log'.format(xtal, xtal)) - else: - Cmd = (pdb_extract_init + - ' -r {0!s}'.format(refSoft) + - ' -iPDB {0!s}'.format('refine.split.bound-state.pdb') + - ' -e MR' - ' -s AIMLESS' - ' -iLOG {0!s}.log'.format(xtal) + - ' -iENT data_template.cif' - ' -o {0!s}.mmcif > {1!s}.mmcif.log'.format(xtal, xtal)) - - self.Logfile.insert(xtal + ': running pdb_extract: ' + Cmd) - os.system(Cmd) - - self.update_model_mmcif_header(xtal) - - if os.path.isfile(xtal+'.mmcif') and os.path.getsize(xtal+'.mmcif') > 20000 : - self.Logfile.insert('%s: model mmcif file successfully created' %xtal) - if self.ground_state: - self.db.execute_statement( - "update depositTable set mmCIF_model_file='{0!s}.mmcif' where CrystalName is '{1!s}' and DimplePANDDApath is '{2!s}'".format(xtal, - xtal,self.panddaDir)) - else: - self.db.execute_statement("update depositTable set mmCIF_model_file='{0!s}.mmcif' where CrystalName is '{1!s}'".format(xtal,xtal)) - fileStatus = True - else: - self.Logfile.error('%s: model mmcif file was not created successfully') - self.add_to_errorList(xtal) - - return fileStatus - - def update_model_mmcif_header(self,xtal): - self.Logfile.insert('%s: updating header of model mmcif file' %xtal) - foundSoftwareBlock = False - amendSoftwareBlock = False - softwareEntry = [] - for i, line in enumerate(fileinput.input(xtal + '.mmcif', inplace=1)): - # if i == 4: sys.stdout.write('\n') # write a blank line after the 5th line - if '_software.pdbx_ordinal' in line: - foundSoftwareBlock = True - if foundSoftwareBlock: - if not line.startswith('_'): - try: - softwareEntry.append(int(line.split()[0])) - except (ValueError,IndexError): - pass - if '#' in line: - amendSoftwareBlock = True - foundSoftwareBlock = False - if '_refine.pdbx_ls_cross_valid_method' in line: - sys.stdout.write('_refine.pdbx_ls_cross_valid_method THROUGHOUT \n') - - elif '_refine.pdbx_starting_model' in line: - sys.stdout.write('_refine.pdbx_starting_model {0!s} \n'.format( - self.data_template_dict['pdbx_starting_model'])) - - elif '_refine.pdbx_method_to_determine_struct' in line: - sys.stdout.write("_refine.pdbx_method_to_determine_struct 'FOURIER SYNTHESIS'\n") - elif '_struct.title ---' in line: -# self.Logfile.warning('structure title was not created by pdb_extract; there might be an issue with REFMAC 5.8.0238') -# self.Logfile.insert('trying to get title from data_template.cif file') - Title = '' - foundTitle = False - for li in open('data_template.cif'): - if li.startswith('_struct.title'): - foundTitle = True - if foundTitle: - if li.replace(' ','').replace('\n','').replace('\r','') == ';': - Title += li - break - Title += li - sys.stdout.write(Title) - elif amendSoftwareBlock: - cifItem = ( - "{0!s} {1!s} ? ? program ? ? 'data reduction' ? ?\n".format(str(max(softwareEntry) + 1), - self.data_template_dict[ - 'data_integration_software']) + - '{0!s} {1!s} ? ? program ? ? phasing ? ?\n'.format(str(max(softwareEntry) + 2), - self.data_template_dict[ - 'phasing_software']) + - '#\n' - "loop_\n" - "_pdbx_related_exp_data_set.ordinal\n" - "_pdbx_related_exp_data_set.data_reference\n" - "_pdbx_related_exp_data_set.metadata_reference\n" - "_pdbx_related_exp_data_set.data_set_type\n" - "_pdbx_related_exp_data_set.details\n" - " 1 " - " 'doi:%s' " %self.zenodo_dict['ZenodoDOI']+ - " 'doi:%s' " %self.zenodo_dict['ZenodoDOI']+ - " 'other data' " # 'other data' is only thing wwPDB accepts at the moment - " 'Complete PanDDA analysis'\n" - "\n" ) - - sys.stdout.write(cifItem) - amendSoftwareBlock = False - - else: - sys.stdout.write(line) - - - - -# elif '_reflns.d_resolution_low' in line and len(line.split()) == 2: -# sys.stdout.write('_reflns.d_resolution_low {0!s}\n'.format(min(low_reso_list))) -# -# elif '_refine.ls_d_res_low' in line and len(line.split()) == 2: -# sys.stdout.write('_refine.ls_d_res_low {0!s}\n'.format(min(low_reso_list))) - - - def make_table_one(self,xtal): - os.chdir(os.path.join(self.projectDir, xtal)) - if os.path.isfile(xtal + '.mmcif') and os.path.getsize(xtal + '.mmcif') > 20000: - self.Logfile.insert('making table_1 for %s.mmcif' %xtal) - if os.path.isdir('/dls'): - extract_table_init = 'source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n' - extract_table_init += '/dls/science/groups/i04-1/software/pdb-extract-prod/bin/extract_table' - else: - extract_table_init = 'source ' + os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/setup.sh') + '\n' - extract_table_init += +os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/bin/extract_table') - - Cmd = extract_table_init + ' ' + xtal + '.mmcif' - - self.Logfile.insert(xtal + ': running sf_convert: ' + Cmd) - os.system(Cmd) - - if os.path.isfile('cryst-table-1.out'): - os.system('/bin/mv cryst-table-1.out %s-table-1.txt' %xtal) - self.Logfile.insert('%s: table_1 successfully created; updating database...' %xtal) - self.db.execute_statement("update mainTable set table_one='{0!s}-table-1.txt' where CrystalName is '{1!s}'".format(xtal,xtal)) - else: - self.Logfile.warning('%s: could not create table_1' %xtal) - - - def create_sf_mmcif(self,xtal): - fileStatus = False - if self.ground_state: - os.chdir(self.projectDir) - else: - os.chdir(os.path.join(self.projectDir, xtal)) - - if os.path.isfile('no_pandda_analysis_performed'): - mtzin = 'refine.mtz ' - else: - mtzin = 'refine.mtz ' + xtal + '.free.mtz ' - for event in self.eventList: - mtzin += event + ' ' - - if self.ground_state: - mtzin = self.ground_state_mean_mtz - - if os.path.isdir('/dls'): - pdb_extract_init = 'source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n' - pdb_extract_init += '/dls/science/groups/i04-1/software/pdb-extract-prod/bin/sf_convert' - else: - pdb_extract_init = 'source ' + os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/setup.sh') + '\n' - pdb_extract_init += +os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/bin/sf_convert') - - Cmd = (pdb_extract_init + - ' -o mmcif' - ' -sf %s' % mtzin + - ' -out {0!s}_sf.mmcif > {1!s}.sf_mmcif.log'.format(xtal, xtal)) - - self.Logfile.insert(xtal + ': running sf_convert: ' + Cmd) - os.system(Cmd) - os.system('/bin/rm sf_format_guess.text mtzdmp.log SF_4_validate.cif sf_information.cif') - - self.update_sf_mmcif_file(xtal) - - if os.path.isfile(xtal+'_sf.mmcif') and os.path.getsize(xtal+'_sf.mmcif') > 20000 : - self.Logfile.insert('%s: SF mmcif file successfully created' %xtal) - if self.ground_state: - self.db.execute_statement("update depositTable set mmCIF_SF_file='{0!s}_sf.mmcif' where CrystalName is '{1!s}' and DimplePANDDApath is '{2!s}'".format(xtal,xtal,self.panddaDir)) - else: - self.db.execute_statement("update depositTable set mmCIF_SF_file='{0!s}_sf.mmcif' where CrystalName is '{1!s}'".format(xtal,xtal)) - fileStatus = True - else: - self.Logfile.error('%s: SF mmcif file was not created successfully') - self.add_to_errorList(xtal) - - return fileStatus - - def apo_mmcif_exists(self): - fileStatus = False - self.Logfile.insert('checking if mmcif files of apo structures exist') - counter = 0 - for mmcif in glob.glob(os.path.join(self.panddaDir,'processed_datasets','*','*.mmcif')): - if os.path.isfile(mmcif): - counter += 1 - if counter < 40: - self.Logfile.error('found only %s apo mmcif files' %str(counter)) - self.Logfile.warning('you may need to run "PanDDA tab"/"apo -> mmcif"') - else: - self.Logfile.insert('found %s apo mmcif files; seems OK!' %str(counter)) - fileStatus = True - return fileStatus - - - def add_apo_sf_mmcif_to_ground_state_mmcif(self): - os.chdir(self.projectDir) - self.Logfile.insert('checking pandda directory for apo mmcif files: '+self.panddaDir) - f = open('ground_state_sf.mmcif','a') - counter = 1 - for dirs in glob.glob(os.path.join(self.panddaDir,'processed_datasets','*')): - if not os.path.isdir(dirs): # this is needed in case single files are in processed_datasets - continue - xtal = dirs[dirs.rfind('/')+1:] - self.Logfile.insert('%s: reading saoked compound information from database' %xtal) - xtalDict = self.db.get_db_dict_for_sample(xtal) - if xtalDict['CompoundSMILES'].lower().replace(' ','') == '': - smiles = 'none' - elif 'none' in xtalDict['CompoundSMILES'].lower().replace(' ',''): - smiles = 'none' - elif 'null' in xtalDict['CompoundSMILES'].lower().replace(' ',''): - smiles = 'none' - else: - smiles = xtalDict['CompoundSMILES'].replace(' ','') - self.Logfile.insert('%s: compound SMILES -> %s' %(xtal,smiles)) - if os.path.isfile(os.path.join(dirs,xtal+'_sf.mmcif')): - self.Logfile.insert('adding %s_sf.mmcif to ground-state_sf.mmcif' %xtal) - for line in open(os.path.join(dirs,xtal+'_sf.mmcif')): - if line.startswith('_cell.angle_gamma'): - newLine = line - newLine += '#\n' - newLine += '_diffrn.id 1\n' - newLine += '_diffrn.details "diffraction data from crystal %s; soaked compound: %s"\n' %(str(counter),smiles) - f.write(newLine) - counter += 1 - else: - f.write(line) - f.close() - self.Logfile.insert('added %s apo mmcif files to ground-state mmcif' %str(counter)) - return True - - def add_data_increment_to_apo_mmcif(self): - self.Logfile.insert('inrementing data_rxxxxsf in ground-state_sf.mmcif') - x = ['','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] - a = 0 - b = 0 - c = 0 - - foundFirstLine = False - foundCulprit = False - datasetCounter = 0 - if os.path.isfile(os.path.join(self.panddaDir,'ground_state_sf.mmcif')): - f = open('ground_state_sf_tmp.mmcif','w') - for n,line in enumerate(open(os.path.join(self.panddaDir,'ground_state_sf.mmcif'))): - if line.startswith('data_rxxxxsf') and not foundFirstLine: - foundFirstLine = True - a += 1 - f.write(line) - elif line.startswith('data_rxxxxsf') and foundFirstLine: - if a == len(x): - a = 1 - b += 1 - if b == len(x): - a = 1 - b = 1 - c += 1 - newLine = line.replace('xsf','s%ssf' %str(x[a]+x[b]+x[c])) - datasetCounter += 1 - f.write(newLine) - a += 1 - if datasetCounter % 50 == 0: - self.Logfile.insert('%s data_rxxxxsf records edited...' %str(datasetCounter)) - else: - f.write(line) - f.close() - os.chdir(self.panddaDir) - os.system('/bin/mv ground_state_sf_tmp.mmcif ground_state_sf.mmcif') - return True - - - def event_maps_exist_in_sf_mmcif(self,xtal): - fileOK = False - n_eventMTZ_found = -2 # set to -2 since first two data blocks are initial/final.mtz and data.mtz - if os.path.isfile('no_pandda_analysis_performed'): - self.Logfile.warning('%s: no pandda analysis performed; skipping this step...' %xtal) - fileOK = True - else: - for line in open(xtal + '_sf.mmcif'): - if line.startswith('_refln.crystal_id'): - n_eventMTZ_found += 1 - if n_eventMTZ_found == len(self.eventList): - fileOK = True - self.Logfile.insert('%s: %s_sf.mmcif should contains %s of %s event maps' %(xtal,xtal,n_eventMTZ_found,len(self.eventList))) - else: - self.Logfile.error('%s: %s_sf.mmcif should contains only %s of %s event maps' % ( - xtal, xtal, n_eventMTZ_found, len(self.eventList))) - self.add_to_errorList(xtal) - return fileOK - - - def update_sf_mmcif_file(self,xtal): - self.Logfile.insert('%s: updating %s_sf.mmcif' %(xtal,xtal)) - - if self.ground_state: - bound = [ "data for PanDDA ground-state-mean-map" ] - else: - bound = [ "data from final refinement with ligand, final.mtz", - "data from original reflections, data.mtz", - "data for ligand evidence map (PanDDA event map), event_map_$.mtz" ] - - block = -1 - - self.Logfile.insert('%s: reading wavelength from mtz file; lambda = %s' %(xtal,self.mtz.get_wavelength())) - - if os.path.isfile('no_pandda_analysis_performed'): - self.Logfile.warning('%s: apparently not a pandda deposition; will skip this step...' %xtal) - return None - - for i, line in enumerate(fileinput.input(xtal + '_sf.mmcif', inplace=1)): - - if line.startswith('_cell.length_a'): - block += 1 - - if line.startswith('_cell.angle_gamma'): - if block >= 2: - n = 2 - else: - n = block - sys.stdout.write(line) - newLines = ('#\n' - '_diffrn.id 1\n' - '_diffrn.details "%s"\n' % bound[n]).replace('$',str(block-1)) - sys.stdout.write(newLines) - elif line.startswith('_diffrn_radiation_wavelength.wavelength'): - sys.stdout.write('_diffrn_radiation_wavelength.wavelength {0!s}\n'.format(self.mtz.get_wavelength())) - else: - sys.stdout.write(line) - - - - - -class prepare_for_group_deposition_upload(QtCore.QThread): - - def __init__(self,database,xce_logfile,depositDir,projectDir,type): - QtCore.QThread.__init__(self) - self.database=database - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(database) - self.depositDir=depositDir - self.projectDir=projectDir - self.type=type - - - - def run(self): - - TextIndex='' - os.chdir(self.depositDir) - - # ligand bound structures - if self.type == 'ligand_bound': - self.Logfile.insert('checking depositionTable for mmcif files of ligand-bound structures') - depositList = self.db.execute_statement("select CrystalName from mainTable where RefinementOutcome like '5%';") - xtalString = '(' - for item in depositList: - xtal=str(item[0]) - self.Logfile.insert('%s: adding mmcif files to final tar.bz2 file' %xtal) - xtalString += "CrystalName = '"+xtal+"' or " - xtalString = xtalString[:-4] + ')' - toDeposit=self.db.execute_statement("select CrystalName,mmCIF_model_file,mmCIF_SF_file,DimplePANDDApath from depositTable where StructureType is 'ligand_bound' and %s;" %xtalString) - elif self.type == 'ground_state': - self.Logfile.insert('checking depositionTable for mmcif files of ground-state structures') - toDeposit = self.db.execute_statement("select CrystalName,mmCIF_model_file,mmCIF_SF_file,DimplePANDDApath from depositTable where StructureType is 'ground_state';") - else: - return - - for n,item in enumerate(sorted(toDeposit)): - xtal=str(item[0]) - if self.type == 'ligand_bound': - mmcif=os.path.join(self.projectDir,xtal,str(item[1])) - mmcif_sf=os.path.join(self.projectDir,xtal,str(item[2])) - elif self.type == 'ground_state': - mmcif=os.path.join(str(item[3]),str(item[1])) - mmcif_sf=os.path.join(str(item[3]),str(item[2])) - else: - continue - self.Logfile.insert('%s: %s/ %s' %(xtal,mmcif,mmcif_sf)) - if os.path.isfile(mmcif) and os.path.isfile(mmcif_sf): - self.Logfile.insert('copying {0!s} to {1!s}'.format(mmcif, self.depositDir)) - os.system('/bin/cp {0!s} .'.format(mmcif)) - if self.type == 'ground_state': - os.system('/bin/mv ground_state.mmcif ground_state_{0!s}.mmcif'.format(str(n))) - mmcif = mmcif.replace('ground_state.mmcif','ground_state_{0!s}.mmcif'.format(str(n))) - self.Logfile.insert('copying {0!s} to {1!s}'.format(mmcif_sf, self.depositDir)) - os.system('/bin/cp {0!s} .'.format(mmcif_sf)) - if self.type == 'ground_state': - os.system('/bin/mv ground_state_sf.mmcif ground_state_{0!s}_sf.mmcif'.format(str(n))) - mmcif_sf = mmcif_sf.replace('ground_state_sf.mmcif', 'ground_state_{0!s}_sf.mmcif'.format(str(n))) - else: - self.Logfile.error('cannot find mmcif file for '+xtal) - - text = ( 'label: {0!s}-{1!s}\n'.format(xtal,self.type)+ - 'description: {0!s} structure of {1!s}\n'.format(self.type,xtal)+ - 'model: {0!s}\n'.format(mmcif[mmcif.rfind('/')+1:])+ - 'sf: {0!s}\n\n'.format(mmcif_sf[mmcif_sf.rfind('/')+1:]) ) - TextIndex+=text - - f = open('index.txt','w') - f.write(TextIndex) - f.close() - - # checking of tar.bz2 files exisit - fileList = [] - for i in sorted(glob.glob('%s_structures.tar.bz2.*' %self.type)): - fileList.append(int(i[i.rfind('.')+1:])) - - if os.path.isfile('%s_structures.tar.bz2' %self.type): - if fileList == []: - self.Logfile.warning('moving existing %s_structures.tar.bz2 to %s_structures.tar.bz2.1' %(self.type,self.type)) - os.system('/bin/mv %s_structures.tar.bz2 %s_structures.tar.bz2.1' %(self.type,self.type)) - else: - self.Logfile.warning('moving existing %s_structures.tar.bz2 %s_structures.tar.bz2.%s' %(self.type,self.type,str(max(fileList)+1))) - os.system('/bin/mv %s_structures.tar.bz2 %s_structures.tar.bz2.%s' %(self.type,self.type,str(max(fileList)+1))) - - self.Logfile.insert('preparing tar archive...') - os.system('tar -cvf {0!s}_structures.tar *mmcif index.txt'.format(self.type)) - self.Logfile.insert('bzipping archive...') - os.system('bzip2 {0!s}_structures.tar'.format(self.type)) - self.Logfile.insert('removing all bound mmcif files and index.txt file from '+self.depositDir) - os.system('/bin/rm -f *mmcif index.txt') - self.Logfile.insert('done!') - - - -# # apo structures -# TextIndex='' -# toDeposit=self.db.execute_statement("select CrystalName,mmCIF_model_file,mmCIF_SF_file from depositTable where StructureType is 'apo';") -# for item in sorted(toDeposit): -# xtal=str(item[0]) -# mmcif=str(item[1]) -# mmcif_sf=str(item[2]) -# if os.path.isfile(mmcif) and os.path.isfile(mmcif_sf): -# self.Logfile.insert('copying {0!s} to {1!s}'.format(mmcif, self.depositDir)) -# os.system('/bin/cp {0!s} .'.format(mmcif)) -# self.Logfile.insert('copying {0!s} to {1!s}'.format(mmcif_sf, self.depositDir)) -# os.system('/bin/cp {0!s} .'.format(mmcif_sf)) -# else: -# self.Logfile.insert('cannot find apo mmcif file for '+xtal+' => ERROR') -# -# text = ( 'label: {0!s}-apo\n'.format(xtal)+ -# 'description: apo structure of {0!s}\n'.format(xtal)+ -# 'model: {0!s}\n'.format(mmcif[mmcif.rfind('/')+1:])+ -# 'sf: {0!s}\n\n'.format(mmcif_sf[mmcif_sf.rfind('/')+1:]) ) -# TextIndex+=text -# -# f = open('index.txt','w') -# f.write(TextIndex) -# f.close() -# -# self.Logfile.insert('preparing tar archive...') -# os.system('tar -cvf apo_structures.tar *apo* index.txt') -# self.Logfile.insert('bzipping archive...') -# os.system('bzip2 apo_structures.tar') -# self.Logfile.insert('removing all apo mmcif files and index.txt file from '+self.depositDir) -# os.system('/bin/rm -f *apo*mmcif index.txt') -# self.Logfile.insert('done!') -# - - - -class import_PDB_IDs(QtCore.QThread): - def __init__(self,pdbCodes,database,xce_logfile): - QtCore.QThread.__init__(self) - self.pdbCodes=pdbCodes - self.database=database - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(database) - - def run(self): - - for line in self.pdbCodes.split('\n'): - if len(line.split('/')) == 2 and '-ligand_bound' in line: - xtal=line[:line.rfind('-ligand_bound')].replace(' ','') - pdbID=line.split('/')[1].replace(' ','') - self.Logfile.insert('setting PDB ID for '+xtal+' to '+pdbID) - sqlite="UPDATE mainTable SET Deposition_PDB_ID='{0!s}',RefinementOutcome='6 - Deposited' where CrystalName is '{1!s}';".format(pdbID, xtal) - self.db.execute_statement(sqlite) - - -class compare_smiles_in_db_with_ligand_in_pdb(QtCore.QThread): - def __init__(self,projectDir,database,xce_logfile): - QtCore.QThread.__init__(self) - self.projectDir=projectDir - self.database=database - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(database) - self.ErrorDict={} - - def update_ErrorDict(self,xtal,message): - if xtal not in self.ErrorDict: - self.ErrorDict[xtal]=[] - self.ErrorDict[xtal].append(message) - - def run(self): - - os.chdir(self.projectDir) - - progress_step=1 - if len(glob.glob('*')) != 0: - progress_step=100/float(len(glob.glob('*'))) - else: - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - - for xtal in sorted(glob.glob('*')): - if os.path.isfile(os.path.join(xtal,'refine.pdb')): - smiles=self.db.execute_statement("select CompoundSmiles,CompoundCode from mainTable where CrystalName is '{0!s}'".format(xtal)) - try: - LigandSmiles=str(smiles[0][0]) - LigandCode=str(smiles[0][1]) - elementDict_smiles=smilestools(LigandSmiles).ElementDict() - except IndexError: - self.Logfile.error("{0!s}: something is seems to be wrong with the CompoundCode or SMILES string: {1!s}".format(xtal, str(smiles))) - continue - - pdb=pdbtools(os.path.join(xtal,'refine.pdb')) - ligandList=pdb.ligand_details_as_list() - for ligand in ligandList: - resname = ligand[0] - chainID = ligand[1] - resseq = ligand[2] - altLoc = ligand[3] - elementDict_ligand=pdb.ElementDict(resname,chainID,resseq,altLoc) - for element in elementDict_ligand: - if elementDict_ligand[element] != elementDict_smiles[element]: - self.Logfile.error('{0!s}: {1!s} {2!s} {3!s} {4!s} contains different number of atoms than smiles in DB: {5!s} -> {6!s}'.format(xtal, resname, chainID, resseq, altLoc, LigandSmiles, LigandCode)) - self.update_ErrorDict(xtal, '{0!s} {1!s} {2!s} {3!s} contains different number of atoms than smiles in DB'.format(resname, chainID, resseq, altLoc)) - break - - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL('show_error_dict'), self.ErrorDict) diff --git a/lib/XChemDialogs.py b/lib/XChemDialogs.py deleted file mode 100755 index 921ee67f..00000000 --- a/lib/XChemDialogs.py +++ /dev/null @@ -1,54 +0,0 @@ -import sys -from PyQt4 import QtGui, QtCore - -import XChemDB - -class select_columns_to_show(QtGui.QDialog): - def __init__(self, data_source_file,parent = None): - super(select_columns_to_show, self).__init__(parent) - self.columns_in_data_source=XChemDB.data_source(data_source_file).return_column_list() - - self.column_dict={} - - layout = QtGui.QVBoxLayout(self) - number_of_entries=len(self.columns_in_data_source) - columns_shown_in_dialog_column=25 - grid = QtGui.QGridLayout() - x=0 - y=0 - columns_to_ignore=['Sample ID','ID'] - for entries_added in range(number_of_entries): - if not self.columns_in_data_source[entries_added][1] in columns_to_ignore: - data_source_column = QtGui.QCheckBox(self.columns_in_data_source[entries_added][1]) - self.column_dict[entries_added]=data_source_column -# data_source_column.toggle() - grid.addWidget(data_source_column, y,x) - y+=1 - if y==columns_shown_in_dialog_column: - y=0 - x+=1 - layout.addLayout(grid) - - - # OK and Cancel buttons - buttons = QtGui.QDialogButtonBox( - QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel, - QtCore.Qt.Horizontal, self) - buttons.accepted.connect(self.accept) - buttons.rejected.connect(self.reject) - layout.addWidget(buttons) - - def data_source_column_active(self): - columns_to_show=['Sample ID'] - for key in self.column_dict: - if self.column_dict[key].isChecked(): - columns_to_show.append(self.columns_in_data_source[key][1]) - return columns_to_show - - # static method to create the dialog and return (date, time, accepted) - @staticmethod - def return_selected_columns(parent = None): - dialog = select_columns_to_show(parent) - result = dialog.exec_() - columns = dialog.data_source_column_active() - return (columns,result == QtGui.QDialog.Accepted) diff --git a/lib/XChemLigand.py b/lib/XChemLigand.py deleted file mode 100755 index 45f1f38a..00000000 --- a/lib/XChemLigand.py +++ /dev/null @@ -1,11 +0,0 @@ -import rdkit -from rdkit import Chem -from rdkit.Chem import AllChem - -def generate_steroisomers(input_smiles): - """ - Function to generate all stereoisomers from a SMILES String. Only works on latest version of RDKit. - """ - mol = Chem.MolFromSmiles(input_smiles) - out_mols = AllChem.EnumerateStereoisomers(mol,AllChem.StereoEnumerationOptions(onlyUnassigned=False,tryEmbedding=True)) - return [Chem.MolToSmiles(x,isomericSmiles=True) for x in out_mols] diff --git a/lib/XChemLog.py b/lib/XChemLog.py deleted file mode 100755 index d67d7213..00000000 --- a/lib/XChemLog.py +++ /dev/null @@ -1,128 +0,0 @@ -# last edited: 09/02/2017, 15:00 - -from __future__ import print_function -import os,glob -import sys -from datetime import datetime - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -class startLog: - - def __init__(self,logfile): - self.logfile=logfile - - def create_logfile(self,version): - - pasteVersion=version - for i in range(0,20-len(version)): - pasteVersion+=' ' - - message = ( - '\n\n' - ' #######################################################################\n' - ' # #\n' - ' # XCHEMEXPLORER - multi dataset analysis #\n' - ' # #\n' - ' # Version: %s #\n' %pasteVersion+ - ' # #\n' - ' # Date: 03/12/2019 #\n' - ' # #\n' - ' # Authors: Tobias Krojer, Structural Genomics Consortium, Oxford, UK #\n' - ' # tobias.krojer@sgc.ox.ac.uk #\n' - ' # #\n' - ' # Rachael Skyner, Diamond Light Source, UK #\n' - ' # rachael.skyner@diamond.ac.uk #\n' - ' # #\n' - ' #######################################################################\n' - '\n' - ) - - if not os.path.isfile(self.logfile): - os.system('touch '+self.logfile) - message+='creating new logfile for the current XChemExplorer ('+version+') session:\n'+self.logfile+'\n' - - else: - message+='writing into existing logfile for current XChemExplorer ('+version+') session:\n'+self.logfile+'\n' - updateLog(self.logfile).insert(message) - #print(message) - -class depositLog: - - def __init__(self,logfile): - self.logfile=logfile - self.suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] - - def humansize(self,nbytes): - if nbytes == 0: return '0 B' - i = 0 - while nbytes >= 1024 and i < len(self.suffixes)-1: - nbytes /= 1024. - i += 1 - f = ('{0:.2f}'.format(nbytes)).rstrip('0').rstrip('.') - return '{0!s} {1!s}'.format(f, self.suffixes[i]) - - def modelInfo(self,xtal,structureType): - message=(xtal+' @ '+structureType) - updateLog(self.logfile).insert(message) - - def nEvents(self,xtal,n_eventMtz): - updateLog(self.logfile).insert(xtal+' contains '+str(n_eventMtz)+ ' sites which are ready for deposition') - - def site_xml(self,xtal,xml): - updateLog(self.logfile).insert('site description for '+xtal) - updateLog(self.logfile).insert(xml) - - def text(self,message): - updateLog(self.logfile).insert(message) - - def summary(self,n_toDeposit,success,failureDict,structureType,successDict): - message= ( '\n' - '==========================================================================\n' - 'SUMMARY:\n' - '--------------------------------------------------------------------------\n' - ' - structure type: %s\n' %structureType+ - ' - n(structures to deposit): {0!s}\n'.format(str(n_toDeposit))+ - ' - n(successful mmcif): {0!s}\n'.format(str(success))+ - '--------------------------------------------------------------------------\n' ) - - if successDict != {}: - message+='\n => the following structures were successfully created:\n' - message+='--------------------------------------------------------------------------\n' - for key in sorted(successDict): - message+='{0:20} {1:5} {2:25} {3:10} {4:25} {5:10}\n'.format(key,'->',successDict[key][0],str(self.humansize(successDict[key][1])),successDict[key][2],str(self.humansize(successDict[key][3]))) - - - if failureDict != {}: - message+='--------------------------------------------------------------------------\n' - message+='\n => the following structures had a problem:\n' - message+='--------------------------------------------------------------------------\n' - for key in failureDict: - for entry in failureDict[key]: - message+='{0!s} -> {1!s}\n'.format(key, entry) - - message+='==========================================================================\n\n' - - updateLog(self.logfile).insert(message) - -class updateLog: - - def __init__(self,logfile): - self.logfile=open(logfile, "a") - - def insert(self,message): - present_time=datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') - print( str(present_time)+' ==> XCE: '+message, file = self.logfile) - print('==> XCE: '+message) - - def warning(self,message): - present_time=datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') - print( str(present_time)+' ==> XCE: WARNING! '+message, file = self.logfile) - print('==> XCE: WARNING! '+message) - - def error(self,message): - present_time=datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') - print( str(present_time)+' ==> XCE: ERROR!!! '+message, file = self.logfile) - print('==> XCE: ERROR!!! '+message) - - diff --git a/lib/XChemMain.py b/lib/XChemMain.py deleted file mode 100755 index 629ca421..00000000 --- a/lib/XChemMain.py +++ /dev/null @@ -1,1284 +0,0 @@ -# last edited: 15/05/2017, 15:00 - -import os,glob -import sys -import subprocess -import getpass -import gzip -from datetime import datetime -from PyQt4 import QtGui, QtCore - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -import XChemDB -import XChemLog - - -def space_group_list(): - space_group_list = [ 'P1', - 'P2','P21','C121','P1211','P121','I2','I121', - 'P222','P2122','P2212','P2221', - 'P21212','P21221','P22121','P212121', - 'C222','C2221','F222', 'I222', 'I212121', - 'P4','P41','P42','P43','I4','I41', - 'P422','P4212','P4122','P41212','P4222', - 'P42212','P4322','P43212','I422','I4122' , - 'P3','P31','P32', - 'P312','P321','P3112','P3121','P3212','P3221', - 'P6','P61','P65','P62','P64','P63', - 'P622','P6122','P6522','P6222','P6422','P6322', - 'H3','H32', - 'P23','F23','I23','P213','I213', - 'P432','P4232','F432','F4132','I432','P4332','P4132','I4132' ] - return space_group_list - - -def get_target_and_visit_list(beamline_directory,agamemnon): -# target_list=['*'] # always give the option to read in all targets - target_list=['=== SELECT TARGET ===','=== project directory ==='] - visit_list=[] - # the beamline directory could be a the real directory or - # a directory where the visits are linked into - if agamemnon: - # /dls/i03/data/2019/lb18145-136 - for target in glob.glob(beamline_directory[:beamline_directory.rfind('-') + 1] + '*/agamemnon/*'): - visit_list.append(beamline_directory[:beamline_directory.rfind('/')].replace('/agamemnon','')) - if target[target.rfind('/') + 1:] not in ['results', 'README-log', 'edna-latest.html']: - if target[target.rfind('/') + 1:] not in target_list: - target_list.append(target[target.rfind('/') + 1:]) - for target in glob.glob(beamline_directory[:beamline_directory.rfind('-') + 1] + '*/auto/*'): - visit_list.append(beamline_directory[:beamline_directory.rfind('/')].replace('/auto', '')) - if target[target.rfind('/') + 1:] not in ['results', 'README-log', 'edna-latest.html']: - if target[target.rfind('/') + 1:] not in target_list: - target_list.append(target[target.rfind('/') + 1:]) - else: - if len(beamline_directory.split('/')) and \ - beamline_directory.split('/')[1]=='dls' and beamline_directory.split('/')[3]=='data' \ - and not 'labxchem' in beamline_directory: - visit_list.append(beamline_directory) - else: - visit_list.append(os.path.realpath(beamline_directory)) - - for visit in visit_list: - print '-->',os.path.join(visit,'processed','*') - for target in glob.glob(os.path.join(visit,'processed','*')): - print target - if target[target.rfind('/')+1:] not in ['results','README-log','edna-latest.html']: - if target[target.rfind('/')+1:] not in target_list: - target_list.append(target[target.rfind('/')+1:]) - return target_list,visit_list - -#def get_target_and_visit_list_for_Pietro(beamline_directory): -## target_list=['*'] # always give the option to read in all targets -# target_list=['=== SELECT TARGET ==='] # always give the option to read in all targets -# visit_list=[] -# # the beamline directory could be a the real directory or -# # a directory where the visits are linked into -# for stuff in glob.glob(os.path.join(beamline_directory,'*')): -# visit_list.append(stuff) -# -# for visit in visit_list: -# for target in glob.glob(os.path.join(visit,'processed','*')): -# if target[target.rfind('/')+1:] not in ['results','README-log','edna-latest.html']: -# if target[target.rfind('/')+1:] not in target_list: -# target_list.append(target[target.rfind('/')+1:]) -# return target_list,visit_list - - -def get_dewar_configuration(beamline_directory): - dewar_sample_configuration_dict={} - # need to do it like this for now until we got a way to query ispyb - for xml in glob.glob(os.path.join(beamline_directory,'xml','exptTableParams-*.xml')): - prefix='' - container_reference='' - sample_location='' - for line in open(xml): - if 'prefix' in line: - prefix=line[line.find('>')+1:line.rfind('<')] - if 'container_reference' in line: - container_reference=line[line.find('>')+1:line.rfind('<')] - if 'sample_location' in line: - sample_location=line[line.find('>')+1:line.rfind('<')] - dewar_sample_configuration_dict[str(container_reference)+'-'+str(sample_location)]=prefix - return dewar_sample_configuration_dict - -def get_jobs_running_on_cluster(): - out_dict={} - - dimple_jobs=[] - acedrg_jobs=[] - pandda_jobs=[] - refmac_jobs=[] - xia2_jobs=[] - others_jobs=[] - - # note: each job_details list contains a list with - # [job_ID, status, run_time] - out=subprocess.Popen(['qstat'],stdout=subprocess.PIPE) - for n,line in enumerate(iter(out.stdout.readline,'')): - if len(line.split()) >= 7: - if line.split()[3] == getpass.getuser(): - - job_id = line.split()[0] - job_name = line.split()[2] - job_status = line.split()[4] - - ########################################################## - # determine run time of each job in minutes - start_date='' - start_time='' - run_time_minutes='' - start_date=line.split()[5] - if len(start_date.split('/')) == 3: - month_start=start_date.split('/')[0] - day_start=start_date.split('/')[1] - year_start=start_date.split('/')[2] - - start_time=line.split()[6] - if len(start_time.split(':')) == 3: - hour_start=start_time.split(':')[0] - minute_start=start_time.split(':')[1] - second_start=start_time.split(':')[2] - - if start_time != '' and start_date != '': - start='{0!s}-{1!s}-{2!s} {3!s}:{4!s}:{5!s}'.format(year_start, month_start, day_start, hour_start, minute_start, second_start) - run_time=datetime.now()-datetime.strptime(start,"%Y-%m-%d %H:%M:%S") - run_time_seconds=int(run_time.total_seconds()) - run_time_minutes=int(run_time.total_seconds() / 60) - run_time_hours=int(run_time.total_seconds() / 3600) - - ########################################################## - # determine run time of each job in minutes - if 'dimple' in job_name: - dimple_jobs.append([job_id,job_status,run_time_minutes]) - elif 'acedrg' in job_name: - acedrg_jobs.append([job_id,job_status,run_time_minutes]) - elif 'pandda' in job_name: - pandda_jobs.append([job_id,job_status,run_time_minutes]) - elif 'refmac' in job_name: - refmac_jobs.append([job_id,job_status,run_time_minutes]) - elif 'xia2' in job_name: - xia2_jobs.append([job_id,job_status,run_time_minutes]) - else: - others_jobs.append([job_id,job_status,run_time_minutes]) - - out_dict['dimple']=dimple_jobs - out_dict['acedrg']=acedrg_jobs - out_dict['pandda']=pandda_jobs - out_dict['refmac']=refmac_jobs - out_dict['xia2']=xia2_jobs - out_dict['others']=others_jobs - - return out_dict - -def print_acedrg_status(xce_logfile,xtal_db_dict): - Logfile=XChemLog.updateLog(xce_logfile) - Logfile.insert('compound restraints summary:') - pending=0 - started=0 - running=0 - missing_smiles=0 - failed=0 - success=0 - unknown=0 - for xtal in xtal_db_dict: - db_dict=xtal_db_dict[xtal] - status=db_dict['RefinementCIFStatus'] - if 'pending' in status: - pending+=1 - elif 'started' in status: - started+=1 - elif 'running' in status: - running+=1 - elif 'missing' in status: - missing_smiles+=1 - elif 'failed' in status: - failed +=1 - elif 'generated' in status: - success+=1 - else: - unknown+=1 - Logfile.insert('restraint generation pending: ...... {0!s}'.format(str(pending))) - Logfile.insert('restraint generation started: ...... {0!s}'.format(str(started))) - Logfile.insert('restraint generation running: ...... {0!s}'.format(str(running))) - Logfile.insert('missing smiles string: ............. {0!s}'.format(str(missing_smiles))) - Logfile.insert('restraint generation failed: ....... {0!s}'.format(str(failed))) - Logfile.insert('restraints successfully created: ... {0!s}'.format(str(success))) - Logfile.insert('unknown status: .................... {0!s}'.format(str(unknown))) - -def print_cluster_status_message(program,cluster_dict,xce_logfile): - Logfile=XChemLog.updateLog(xce_logfile) - Logfile.insert('cluster status summary:') - Logfile.insert('{0!s} {1!s} jobs are running on the cluster'.format(len(cluster_dict[program]), program)) - if len(cluster_dict[program]) > 0: - cumulative_runtime=0 - job_ids = [] - for n,item in enumerate(cluster_dict[program]): - cumulative_runtime += item[2] - if not item[0] in job_ids: - job_ids.append(item[0]) - average_runtime=round(float(cumulative_runtime)/float(n+1),0) - Logfile.insert('average run time '+str(average_runtime)+' minutes') - if job_ids: - Logfile.insert('you can kill them by pasting the following line into a new terminal window:') - out='qdel ' - for job in job_ids: - out += str(job)+' ' - Logfile.insert(out) - - - -def display_queue_status_in_terminal(in_dict): - # latest_run=max(tmp,key=lambda x: x[1])[0] - max_dimple_runtime=max(in_dict['dimple'],key=lambda x:x[2])[2] - print '----------------------------------------------------------------------------' - print '| Task | Nr. Jobs | Max. Runtime (minutes) |' - print '----------------------------------------------------------------------------' - print '{0:24} {1:24} {2:24} {3:1}'.format('| DIMPLE', '| {0!s}'.format(len(in_dict['dimple'])),'| %s' &max_dimple_runtime,'|') - print '----------------------------------------------------------------------------' - -def get_datasource_summary(db_file): - db=XChemDB.data_source(db_file) - - out_dict={} - - out_dict['nr_samples']=len(db.execute_statement("select CrystalName from mainTable where CrystalName is not NULL;")) - out_dict['nr_samples_failed_to_mount']=len(db.execute_statement("select HarvestStatus from mainTable where HarvestStatus is 'fail';")) - - out_dict['nr_smiles_for_samples']=len(db.execute_statement("select compoundSMILES from mainTable where compoundSMILES is not (NULL or '')")) - - out_dict['nr_data_collection_success']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'success';")) - out_dict['nr_data_collection_centring_fail']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - centring failed';")) - out_dict['nr_data_collection_no-diffraction']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - no diffraction';")) - out_dict['nr_data_collection_processing_fail']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - processing';")) - out_dict['nr_data_collection_loop-empty']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - loop empty';")) - out_dict['nr_data_collection_loop-broken']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - loop broken';")) - out_dict['nr_data_collection_low-resolution']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - low resolution';")) - out_dict['nr_data_collection_no-X-rays']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - no X-rays';")) - out_dict['nr_data_collection_unknown']=len(db.execute_statement("select DataCollectionOutcome from mainTable where DataCollectionOutcome is 'Failed - unknown';")) - - out_dict['nr_data_collection_failed']= out_dict['nr_data_collection_centring_fail'] + \ - out_dict['nr_data_collection_no-diffraction'] + \ - out_dict['nr_data_collection_processing_fail'] + \ - out_dict['nr_data_collection_loop-empty'] + \ - out_dict['nr_data_collection_loop-broken'] + \ - out_dict['nr_data_collection_low-resolution'] + \ - out_dict['nr_data_collection_no-X-rays'] + \ - out_dict['nr_data_collection_unknown'] - - - out_dict['nr_data_collection_pending']=out_dict['nr_samples'] - out_dict['nr_data_collection_success'] - \ - out_dict['nr_data_collection_centring_fail'] - \ - out_dict['nr_data_collection_no-diffraction'] - \ - out_dict['nr_data_collection_processing_fail'] - \ - out_dict['nr_data_collection_loop-empty'] - \ - out_dict['nr_data_collection_loop-broken'] - \ - out_dict['nr_data_collection_low-resolution'] - \ - out_dict['nr_data_collection_no-X-rays'] - \ - out_dict['nr_data_collection_unknown'] - - out_dict['nr_initial_maps_available']=len(db.execute_statement("select DimplePathToMTZ from mainTable where DimplePathToMTZ is not '';")) - out_dict['nr_initial_maps_fail']=len(db.execute_statement("select DataProcessingDimpleSuccessful from mainTable where DataProcessingDimpleSuccessful = 'False';")) - out_dict['nr_initial_maps_pending']=out_dict['nr_data_collection_success']-out_dict['nr_initial_maps_available']-out_dict['nr_initial_maps_fail'] - - out_dict['nr_pandda_hits']=len(db.execute_statement("select DimplePANDDAhit from mainTable where DimplePANDDAhit = 'True';")) - out_dict['nr_pandda_reject']=len(db.execute_statement("select DimplePANDDAreject from mainTable where DimplePANDDAreject = 'True';")) - out_dict['nr_pandda_processed']=len(db.execute_statement("select DimplePANDDAwasRun from mainTable where DimplePANDDAwasRun = 'True';"))-out_dict['nr_pandda_hits']-out_dict['nr_pandda_reject'] - out_dict['nr_pandda_pending']=out_dict['nr_initial_maps_available']-out_dict['nr_pandda_hits']-out_dict['nr_pandda_reject']-out_dict['nr_pandda_processed'] - - out_dict['nr_cif_files']=len(db.execute_statement("select RefinementCIF from mainTable where RefinementCIF is not (Null or '');")) - - out_dict['nr_analysis-pending']=len(db.execute_statement("select RefinementOutcome from mainTable where RefinementOutcome is '1 - Analysis Pending';")) - out_dict['nr_pandda-models']=len(db.execute_statement("select RefinementOutcome from mainTable where RefinementOutcome is '2 - PANDDA model';")) - out_dict['nr_in-refinement']=len(db.execute_statement("select RefinementOutcome from mainTable where RefinementOutcome is '3 - In Refinement';")) - out_dict['nr_comp-chem-ready']=len(db.execute_statement("select RefinementOutcome from mainTable where RefinementOutcome is '4 - ComChem ready';")) - out_dict['nr_deposition-ready']=len(db.execute_statement("select RefinementOutcome from mainTable where RefinementOutcome is '5 - Deposition ready';")) - - return out_dict - - -def remove_all_refmac_jobs_from_cluster_and_reinstate_last_stable_state(): - print 'hallo' - - -def change_links_to_selected_data_collection_outcome(sample,data_collection_dict,data_collection_column_three_dict,dataset_outcome_dict,initial_model_directory,data_source_file,xce_logfile): - Logfile=XChemLog.updateLog(xce_logfile) - # find out which row was selected in respective data collection table - selected_processing_result='n/a' - indexes=data_collection_column_three_dict[sample][0].selectionModel().selectedRows() - if indexes: # i.e. logfile exists - for index in sorted(indexes): - selected_processing_result=index.row() - - for n,entry in enumerate(data_collection_dict[sample]): - if entry[0]=='logfile': - if entry[7]==selected_processing_result: - visit=entry[1] - run=entry[2] - autoproc=entry[4] - db_dict=entry[6] - outcome=dataset_outcome_dict[sample] - path_to_logfile=db_dict['DataProcessingPathToLogfile'] - path_to_mtzfile=db_dict['DataProcessingPathToMTZfile'] - mtz_filename=db_dict['DataProcessingMTZfileName'] - log_filename=db_dict['DataProcessingLOGfileName'] -# relative_path_to_mtzfile='./'+path_to_mtzfile.replace(initial_model_directory,'') - relative_path_to_mtzfile='./'+path_to_mtzfile.replace(os.path.join(initial_model_directory,sample),'') - if relative_path_to_mtzfile.startswith('.//'): - relative_path_to_mtzfile=relative_path_to_mtzfile.replace('.//','./') - relative_path_to_logfile='./'+path_to_logfile.replace(os.path.join(initial_model_directory,sample),'') - if relative_path_to_logfile.startswith('.//'): - relative_path_to_logfile=relative_path_to_logfile.replace('.//','./') - - - # first check if folders and files exist - # since user might do this before data are actually copied over - - if os.path.isdir(os.path.join(initial_model_directory,sample,'autoprocessing',visit+'-'+run+autoproc)): - db_dict['DataProcessingAutoAssigned']='False' - Logfile.insert('changing directory to: '+os.path.join(initial_model_directory,sample)) - os.chdir(os.path.join(initial_model_directory,sample)) - # first remove old links - os.system('/bin/rm '+sample+'.mtz 2> /dev/null') - os.system('/bin/rm '+sample+'.log 2> /dev/null') - # make new links -# Logfile.insert('setting symlink: '+os.path.join(path_to_logfile,log_filename)+' -> '+sample+'.log') -# os.symlink(os.path.join(path_to_logfile,log_filename),sample+'.log') -# Logfile.insert('setting symlink: '+os.path.join(path_to_mtzfile,mtz_filename)+' -> '+sample+'.mtz') -# os.symlink(os.path.join(path_to_mtzfile,mtz_filename),sample+'.mtz') - Logfile.insert('setting relative symlink: '+os.path.join(relative_path_to_logfile,log_filename)+' -> '+sample+'.log') - os.symlink(os.path.join(relative_path_to_logfile,log_filename),sample+'.log') - Logfile.insert('setting relative symlink: '+os.path.join(relative_path_to_mtzfile,mtz_filename)+' -> '+sample+'.mtz') - os.symlink(os.path.join(relative_path_to_mtzfile,mtz_filename),sample+'.mtz') - - # update data source - data_source=XChemDB.data_source(data_source_file) - data_source.update_insert_data_source(sample,db_dict) - - else: - Logfile.insert('please copy data to PROJECT DIRECTORY first!') - - -#def find_diffraction_image_directory(diffraction_data_directory): -# data_dict={} -# diffraction_image_extension = ['.img','.cbf','.mccd','.mar2560','.mar2300'] -# os.chdir(diffraction_data_directory) -# for xtal in glob.glob('*'): -# data_dict[xtal]=[] -# for root,dirs,files in os.walk(xtal): -# if 'screening' in root: -# continue -# for n,image_file in enumerate(glob.glob(os.path.join(root,'*'))): -# file_extension=image_file[image_file.rfind('.'):] -# if n > 20 and file_extension in diffraction_image_extension: -# data_dict[xtal].append(os.path.join(diffraction_data_directory,root)) -# break -# if data_dict[xtal]==[]: -# del data_dict[xtal] -# return data_dict - -def get_nr_files_from_gda_log_folder(beamline): - n=len(glob.glob(os.path.join('/dls_sw',beamline,'logs','gda_server*'))) - return n - -def get_dict_of_gda_barcodes(beamline): - out_dict={} - for files in glob.glob(os.path.join('/dls_sw',beamline,'logs','*')): - found_barcode_entry=False - gda_log= files[files.rfind('/')+1:] - if gda_log.startswith('gda_server.') and gda_log.endswith('.gz'): - with gzip.open(files,'r') as f: - print 'parsing',files -# for line in fin: - for line in f: - if 'BART SampleChanger - getBarcode() returning' in line: - barcode=line.split()[len(line.split())-1] - found_barcode_entry=True - if found_barcode_entry: - if 'Snapshots will be saved' in line: - sampleID=line.split()[len(line.split())-1].split('/')[-1] - out_dict[sampleID]=barcode - found_barcode_entry=False - elif gda_log.startswith('gda_server.') and gda_log.endswith('.log'): - for line in files: - if 'BART SampleChanger - getBarcode() returning' in line: - barcode=line.split()[len(line.split())-1] - found_barcode_entry=True - if found_barcode_entry: - if 'Snapshots will be saved' in line: - sampleID=line.split()[len(line.split())-1].split('/')[-1] - out_dict[sampleID]=barcode - found_barcode_entry=False - - return out_dict - -def append_dict_of_gda_barcodes(out_dict,files,xce_logfile): -# out_dict={} -# for files in glob.glob(os.path.join('/dls_sw',beamline,'logs','*')): - Logfile=XChemLog.updateLog(xce_logfile) - found_barcode_entry=False - gda_log= files[files.rfind('/')+1:] - if gda_log.startswith('gda_server.') or gda_log.startswith('gda-server.') and gda_log.endswith('.gz'): - with gzip.open(files,'r') as f: - for line in f: - if 'BART SampleChanger - getBarcode() returning' in line: - barcode=line.split()[len(line.split())-1] - found_barcode_entry=True - if found_barcode_entry: - if 'Snapshots will be saved' in line: - sampleID=line.split()[len(line.split())-1].split('/')[-1] - out_dict[sampleID]=barcode - Logfile.insert('found: sample={0!s}, barcode={1!s}, file={2!s}'.format(sampleID, barcode, files)) - found_barcode_entry=False - elif gda_log.startswith('gda_server') or gda_log.startswith('gda-server') and gda_log.endswith('txt'): - for line in open(files): - if 'BART SampleChanger - getBarcode() returning' in line: - barcode=line.split()[len(line.split())-1] - found_barcode_entry=True - if found_barcode_entry: - if 'Snapshots will be saved' in line: - sampleID=line.split()[len(line.split())-1].split('/')[-1] - out_dict[sampleID]=barcode - Logfile.insert('found: sample={0!s}, barcode={1!s}, file={2!s}'.format(sampleID, barcode, files)) - found_barcode_entry=False - - return out_dict - -def get_gda_barcodes(sampleList,gzipped_logs_parsed,gda_log_start_line,beamline,xce_logfile): - Logfile=XChemLog.updateLog(xce_logfile) - Logfile.insert('checking GDA logfile in {0!s}'.format(os.path.join('/dls_sw',beamline,'logs'))) - pinDict = {} - found_barcode_entry=False - for gdaLogFile in glob.glob(os.path.join('/dls_sw',beamline,'logs','gda-server*log*')): - Logfile.insert('parsing {0!s}'.format(gdaLogFile)) - if gzipped_logs_parsed and gdaLogFile.endswith('.gz'): - Logfile.insert('{0!s} was already parsed during this visit'.format(gdaLogFile)) - continue - if gdaLogFile.endswith('.gz'): - try: - with gzip.open(gdaLogFile, 'r') as f: - for line in f: - if 'BART SampleChanger - getBarcode() returning' in line: - barcode = line.split()[len(line.split()) - 1] - found_barcode_entry = True - if found_barcode_entry: - if 'Snapshots will be saved' in line: - sampleID = line.split()[len(line.split()) - 1].split('/')[-1] - if sampleID in sampleList: - pinDict[sampleID] = barcode - Logfile.insert( - 'found: sample={0!s}, barcode={1!s}, file={2!s}'.format(sampleID, barcode, gdaLogFile)) - found_barcode_entry = False - except IOError: - Logfile.warning('cannot open file %s' %gdaLogFile) - else: - for n,line in enumerate(open(gdaLogFile).readlines()[gda_log_start_line:]): - if 'BART SampleChanger - getBarcode() returning' in line: - barcode = line.split()[len(line.split()) - 1] - found_barcode_entry = True - if found_barcode_entry: - if 'Snapshots will be saved' in line: - sampleID = line.split()[len(line.split()) - 1].split('/')[-1] - if sampleID in sampleList: - pinDict[sampleID] = barcode - Logfile.insert( - 'found: sample={0!s}, barcode={1!s}, file={2!s}'.format(sampleID, barcode, gdaLogFile)) - found_barcode_entry = False - try: - gda_log_start_line = gda_log_start_line + n -1 - except UnboundLocalError: - gda_log_start_line = gda_log_start_line - - return pinDict,gda_log_start_line - - -def linkAutoProcessingResult(xtal,dbDict,projectDir,xce_logfile): - Logfile=XChemLog.updateLog(xce_logfile) - - run = dbDict['DataCollectionRun'] - visit = dbDict['DataCollectionVisit'] - autoproc = dbDict['DataProcessingProgram'] - mtzFileAbs = dbDict['DataProcessingPathToMTZfile'] - mtzfile = mtzFileAbs[mtzFileAbs.rfind('/')+1:] - logFileAbs = dbDict['DataProcessingPathToLogfile'] - logfile = logFileAbs[logFileAbs.rfind('/')+1:] - - Logfile.insert('changing directory to ' + os.path.join(projectDir,xtal)) - os.chdir(os.path.join(projectDir,xtal)) - - # MTZ file - Logfile.warning('removing %s.mtz' %xtal) - os.system('/bin/rm %s.mtz' %xtal) - print xtal,os.path.join('autoprocessing', visit + '-' + run + autoproc, mtzfile) - if os.path.isfile(os.path.join('autoprocessing', visit + '-' + run + autoproc, mtzfile)): - os.symlink(os.path.join('autoprocessing', visit + '-' + run + autoproc, mtzfile), xtal + '.mtz') - Logfile.insert('linking MTZ file from different auto-processing pipeline:') - Logfile.insert('ln -s ' + os.path.join('autoprocessing', visit + '-' + run + autoproc, mtzfile) + ' ' + xtal + '.mtz') - # LOG file - Logfile.warning('removing %s.log' %xtal) - os.system('/bin/rm %s.log' %xtal) - if os.path.isfile(os.path.join('autoprocessing', visit + '-' + run + autoproc, logfile)): - os.symlink(os.path.join('autoprocessing', visit + '-' + run + autoproc, logfile), xtal + '.log') - Logfile.insert('linking LOG file from different auto-processing pipeline:') - Logfile.insert('ln -s ' + os.path.join('autoprocessing', visit + '-' + run + autoproc, logfile) + ' ' + xtal + '.log') - - - -def getProgressSteps(iterations): - if iterations == 0: - progress_step = 1 - else: - progress_step = 100 / float(iterations) - return progress_step - -def getVisitAndBeamline(visitDirectory): - visit = 'unknown' - beamline = 'unknown' - if 'attic' in visitDirectory: - try: - visit=visitDirectory.split('/')[6] - beamline=visitDirectory.split('/')[3] - except IndexError: - pass - else: - try: - visit=visitDirectory.split('/')[5] - beamline=visitDirectory.split('/')[2] - except IndexError: - pass - if not visitDirectory.startswith('/dls'): - # this is all a bit of a fudge in case someone transfers a DLS visit directory back home - # does most certainly not catch all possible scenarios - if visitDirectory.split('/')[len(visitDirectory.split('/')) - 2] == 'processed': - visit = visitDirectory.split('/')[len(visitDirectory.split('/')) - 3] - else: - visit = visitDirectory.split('/')[len(visitDirectory.split('/'))-1] - beamline = 'unknown' - return visit,beamline - - - - -def crystal_growth_methods(): - - methods = [ 'VAPOR DIFFUSION, SITTING DROP', - 'VAPOR DIFFUSION, HANGING DROP', - 'BATCH MODE', - 'LIPIDIC CUBIC PHASE', - 'MICROBATCH', - 'MICROFLUIDIC' ] - - return methods - -def wwBeamlines(): - - beamlines = [ 'DIAMOND BEAMLINE I02', - 'DIAMOND BEAMLINE I03', - 'DIAMOND BEAMLINE I04', - 'DIAMOND BEAMLINE I04-1', - 'DIAMOND BEAMLINE I23', - 'DIAMOND BEAMLINE I24' ] - - return beamlines - -def radiationSource(): - - source = [ 'SYNCHROTRON', - 'ROTATING ANODE', - 'SEALED TUBE' ] - - return source - -def detector(): - - detectorPrinciple = [ 'PIXEL', - 'CCD', - 'IMAGE PLATE', - 'CMOS' ] - - return detectorPrinciple - -def detectorType(): - - detector = [ 'DECTRIS PILATUS 2M', - 'DECTRIS PILATUS 2M-F', - 'DECTRIS PILATUS 6M', - 'DECTRIS PILATUS 6M-F', - 'DECTRIS PILATUS 12M', - 'DECTRIS PILATUS3 2M', - 'DECTRIS PILATUS3 6M', - 'DECTRIS EIGER X 9M', - 'DECTRIS EIGER X 16M', - 'ADSC QUANTUM 315', - 'ADSC QUANTUM 315r' ] - - return detector - -def NCBI_taxonomy_ID(): - - taxonomy_dict = { '9606': 'homo sapiens', - '562': 'escherichia coli', - '7108': 'SPODOPTERA FRUGIPERDA', - '5693 ': 'Trypanosoma cruzi' } - - return taxonomy_dict - - -def data_integration_software(): - - software = [ 'XDS', - 'HKL', - 'DENZO', - 'DTREK', - 'MOSFLM' ] - - return software - - -def phasing_software(): - - software = [ 'REFMAC', - 'PHENIX', - 'SOLVE', - 'PHASER', - 'CNS', - 'XPLOR', - 'MLPHARE', - 'SHELX', - 'SNB', - 'BnP', - 'BP3', - 'SHARP', - 'PHASES', - 'WARP' ] - - return software - -def html_header(): - - header = ( - '\n' - '\n' - ' \n' - ' \n' - ' \n' - ' \n' - ' Summary Fragment Hits\n' - ' \n' - ' \n' - ' \n' - ' \n' - '\n' - '\n' - ) - - return header - -def html_ngl(firstPDB,firstEvent,firstMap,firstDiffMap,ligID): - - ligChain = ligID.split('-')[1] - ligResid = ligID.split('-')[2] - - ngl = ( - "\n" - ' \n' - '\n' - ) - - return ngl - -def html_download(protein_name): - - download = ( - '
\n' - '

Human %s - XChem results

\n' %protein_name + - " \n" - ' \n' - '\n' - ) - - return download - -def html_guide(): - - guide = ( - " \n" - "
\n" - "

Ligand-bound models for Summary

Interpreting 'Ligand confidence'

\n" - '

4 - High Confidence: The expected ligand was easily interpretable from clear density, and subsequent refinement was well-behaved. This ligand can be trusted.\n' - '
3 - Clear density, unexpected ligand: Density very clearly showed a well-defined ligand, but that ligand was unexpected in that crystal/dataset. The observed ligand was modelled anyway, because its presence could be explained in some way.\n' - '
2 - Correct ligand, weak density: Though density was weak, it was possible to model the expected ligand, possibly including other circumstantial evidence (e.g. similar ligand in another model).\n' - '
1 - Low Confidence: The ligand model is to be treated with scepticism, because the evidence (density, identity, pose) were not convincing.\n' - "

Interpreting 'Model status':

\n" - '

6 - Deposited: The model has been deposited in the PDB.\n' - '
5 - Deposition ready: The model is fully error-free, in every residue, and is ready for deposition.\n' - '
4 - CompChem ready: The model is complete and correct in the region of the bound ligand. There may be remaining small errors elsewhere in the structure, but they are far away and unlikely to be relevant to any computational analysis or compound design.\n' - "

Interpreting 'Ligand validation' spider plots:

Each axis represents one of the values described below; small is better, and large values on any axis implies that further investigation is warranted.\n" - '

Quality (RSCC) reflects the fit of the atoms to the experimental density, and should typically be greater than 0.7.\n' - '
Accuracy (RSZD) measures the amount of difference density that is found around these atoms, and should be below 3.\n' - '
B-factor ratio measures the consistency of the model with surrounding protein, and is calculated from the B factors of respectively the changed atoms and all side-chain atoms within 4Å. Large values (>3) reflect poor evidence for the model, and intermediate values (1.5+) indicate errors in refinement or modelling; for weakly-binding ligands, systematically large ratios may be justifiable.\n' - '
RMSD compares the positions of all atoms built into event density, with their positions after final refinement, and should be below 1Å.\n' - '
Precision (RSZO/OCC) measures how clear the density is after refinement. (This is not a quality indicator, but is related to strength of binding but not in a straightforward way.)\n' - '

\n' - '

\n' - '\n' - ) - - return guide - -def html_table_header(): - - table = ( - "\n" - '\n' - '\n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - - ) - - - - return table - - -def html_table_row(xtalID,pdbID,ligID,compoundImage,residuePlot,pdb,event,thumbNail,resoHigh,spg,unitCell,FWT,DELFWT,ligConfidence,modelStatus): - - ligChain = ligID.split('-')[1] - ligResid = ligID.split('-')[2] - -# row = ( -# '\n' -# '\n' %xtalID + -# '\n' %(pdbID,pdbID) + -# '\n' %ligID + -# '\n' % ligConfidence + -# '\n' % modelStatus + -# "\n" %compoundImage + -# "\n" %residuePlot + -# "\n" %(pdbID,pdb,event,FWT,DELFWT,ligChain,ligResid,thumbNail) + -# '\n' %resoHigh + -# '\n' %(spg,unitCell) + -# "\n" %(pdb.replace('.pdb',''),ligID) + -# '\n' -# ) - - - row = ( - ' \n' - ' \n' %xtalID + - ' \n' %(pdbID,pdbID) + - ' \n' %ligID + - ' \n' %ligConfidence + - ' \n' %modelStatus + - " \n" %compoundImage + - " \n" %residuePlot + - " \n" %(pdbID,pdb,event,FWT,DELFWT,ligChain,ligResid,thumbNail) + - ' \n' %resoHigh + - ' \n' %(spg,unitCell) + - " \n" %(pdb.replace('.pdb',''),ligID) + - ' \n' - ) - - - return row - -def html_footer(): - - footer = ( - '\n' - '
Crystal IDPDB IDLigand IDLigand confidenceModel statusCompoundLigand ValidationEvent Map 3DResolSPG/ CellFiles
%s%s%s%s%s
%s%s
%s
Save
%s%s%s%s%s
%s%s
%s
Save
\n' - '\n' - '\n' - ) - - return footer - -def coot_prepare_input(x,y,z,ligID,sampleDir,eventMap): - - os.chdir(sampleDir) - cmd = ( - '# !/usr/bin/env coot\n' - '# python script for coot - generated by dimple\n' - 'import coot\n' - 'set_nomenclature_errors_on_read("ignore")\n' - 'molecule = read_pdb("refine.split.bound-state.pdb")\n' - 'set_rotation_centre(%s, %s, %s)\n' %(x,y,z) + - 'set_zoom(30.)\n' - 'set_view_quaternion(-0.180532, -0.678828, 0, 0.711759)\n' - 'coot.handle_read_ccp4_map(("%s"),0)\n' %eventMap + -# 'mtz = "final.mtz"\n' -# 'map21 = make_and_draw_map(mtz, "FWT", "PHWT", "", 0, 0)\n' -# 'map11 = make_and_draw_map(mtz, "DELFWT", "PHDELWT", "", 0, 1)\n' - 'coot.raster3d("%s.r3d")\n' %ligID + - 'coot_real_exit(0)\n' - ) - f = open(ligID+'.py', 'w') - f.write(cmd) - f.close() - -def coot_write_raster_file(ligID,sampleDir): - os.chdir(sampleDir) - os.system('coot --no-graphics --no-guano --script %s.py' %ligID) - -def render_scene(xtal,ligID,sampleDir): - os.chdir(sampleDir) - os.system('render < %s.r3d -png %s_%s.png' %(ligID,xtal,ligID)) - -def make_thumbnail(xtal,ligID,sampleDir): - os.chdir(sampleDir) - os.system('convert -thumbnail 150x150 %s_%s.png %s_%s_thumb.png' %(xtal,ligID,xtal,ligID)) - -class find_diffraction_image_directory(QtCore.QThread): - def __init__(self,diffraction_data_directory): - QtCore.QThread.__init__(self) - self.diffraction_data_directory=diffraction_data_directory - self.data_dict={} - self.diffraction_image_extension = ['.img','.cbf','.mccd','.mar2560','.mar2300'] -# self.datasetID_to_sampleID_conversion='*' - - def run(self): - os.chdir(self.diffraction_data_directory) - if len(glob.glob(os.path.join(self.diffraction_data_directory,'*'))) != 0: - progress_step=100/float(len(glob.glob(os.path.join(self.diffraction_data_directory,'*')))) - else: - progress_step=100 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'searching diffraction data directory') - for xtal in glob.glob('*'): - self.data_dict[xtal]=[[],[]] - for root,dirs,files in os.walk(xtal): - if 'screening' in root: - continue - image_file_list = [] - for n,image_file in enumerate(glob.glob(os.path.join(root,'*'))): - file_extension=image_file[image_file.rfind('.'):] - if file_extension in self.diffraction_image_extension: - image_file_list.append(image_file) - - if n > 20 and file_extension in self.diffraction_image_extension: - if os.path.join(self.diffraction_data_directory,root) not in self.data_dict[xtal][0]: - self.data_dict[xtal][0].append(os.path.join(self.diffraction_data_directory,root)) -# break - if self.data_dict[xtal][0]: - found_new_file_root=False - run_list=[] - counter=0 - current_file_root='' - for image in image_file_list: - file_root=image[image.rfind('/')+1:image.rfind('_')] - if file_root not in run_list and not found_new_file_root: - counter=0 - found_new_file_root=True - current_file_root=file_root - if counter > 20 and file_root not in run_list: - print counter,file_root - run_list.append(file_root) - found_new_file_root=False - counter=0 - if found_new_file_root and file_root==current_file_root: - counter+=1 - - if run_list: - self.data_dict[xtal][1]=run_list - - - if self.data_dict[xtal]==[[],[]]: - del self.data_dict[xtal] - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL('update_datasets_reprocess_table'), self.data_dict) - -class find_diffraction_image_directory_fast(QtCore.QThread): - def __init__(self,diffraction_data_directory): - QtCore.QThread.__init__(self) - self.diffraction_data_directory=diffraction_data_directory - self.data_dict={} - self.diffraction_image_extension = ['.img','.cbf','.mccd','.mar2560','.mar2300'] -# self.datasetID_to_sampleID_conversion='*' - - def run(self): - print('Running diffraction image search in ' + str(self.diffraction_data_directory)) - os.chdir(self.diffraction_data_directory) - if len(glob.glob(os.path.join(self.diffraction_data_directory,'*'))) != 0: - progress_step=100/float(len(glob.glob(os.path.join(self.diffraction_data_directory,'*')))) - else: - progress_step=100 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'searching diffraction data directory') - for xtal in glob.glob('*'): - #print xtal - if 'screening' in xtal: - continue - self.data_dict[xtal]=[] - rootList=[] - imageCounter=0 - - # find image file extension; the assumption is that there is only one file type - imageExtension='cbf' - for files in sorted(glob.glob(os.path.join(xtal,'*'))): - fileName=os.path.join(self.diffraction_data_directory,files) - file_extension=fileName[fileName.rfind('.'):] - if file_extension in self.diffraction_image_extension: - imageExtension=file_extension - break - - for files in sorted(glob.glob(os.path.join(xtal,'*'+imageExtension))): - fileName=files[files.rfind('/')+1:] - file_root=fileName[:fileName.rfind('_')] - - if file_root not in rootList: - rootList.append(file_root) - currentRoot=file_root - imageCounter=0 - - if imageCounter == 20: - self.data_dict[xtal].append([os.path.join(self.diffraction_data_directory,xtal),file_root]) -# self.data_dict[xtal][1].append(file_root) - - imageCounter+=1 - - if not self.data_dict[xtal]: - del self.data_dict[xtal] - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL('update_datasets_reprocess_table'), self.data_dict) - diff --git a/lib/XChemPANDDA.py b/lib/XChemPANDDA.py deleted file mode 100755 index 1d4ecafa..00000000 --- a/lib/XChemPANDDA.py +++ /dev/null @@ -1,1442 +0,0 @@ -# last edited: 10/08/2017, 10:25 - -import os, sys, glob, subprocess -from datetime import datetime -from PyQt4 import QtGui, QtCore -import math -#from XChemUtils import mtztools -import XChemDB -import XChemRefine -import XChemUtils -import XChemLog -import XChemToolTips -import csv - -def get_names_of_current_clusters(xce_logfile,panddas_directory): - Logfile=XChemLog.updateLog(xce_logfile) - Logfile.insert('parsing {0!s}/cluster_analysis'.format(panddas_directory)) - os.chdir('{0!s}/cluster_analysis'.format(panddas_directory)) - cluster_dict={} - for out_dir in sorted(glob.glob('*')): - if os.path.isdir(out_dir): - cluster_dict[out_dir]=[] - found_first_pdb=False - for folder in glob.glob(os.path.join(out_dir,'pdbs','*')): - xtal=folder[folder.rfind('/')+1:] - if not found_first_pdb: - if os.path.isfile(os.path.join(panddas_directory,'cluster_analysis',out_dir,'pdbs',xtal,xtal+'.pdb') ): - cluster_dict[out_dir].append(os.path.join(panddas_directory,'cluster_analysis',out_dir,'pdbs',xtal,xtal+'.pdb')) - found_first_pdb=True - cluster_dict[out_dir].append(xtal) - return cluster_dict - - -class run_pandda_export(QtCore.QThread): - - def __init__(self,panddas_directory,datasource,initial_model_directory,xce_logfile,update_datasource_only,which_models): - QtCore.QThread.__init__(self) - self.panddas_directory=panddas_directory - self.datasource=datasource - self.initial_model_directory=initial_model_directory - self.db=XChemDB.data_source(self.datasource) - self.db.create_missing_columns() - self.db_list=self.db.get_empty_db_dict() - self.external_software=XChemUtils.external_software(xce_logfile).check() - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.update_datasource_only=update_datasource_only - self.which_models=which_models - self.already_exported_models=[] - - self.RefmacParams={ 'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': '' } - - def run(self): - - # v1.3.8.2 - removed option to update database only -# if not self.update_datasource_only: - samples_to_export=self.export_models() - - self.import_samples_into_datasouce(samples_to_export) - -# if not self.update_datasource_only: - self.refine_exported_models(samples_to_export) - - - def refine_exported_models(self,samples_to_export): - self.Logfile.insert('will try to refine the following crystals:') - for xtal in samples_to_export: self.Logfile.insert(xtal) -# sample_list=self.db.execute_statement("select CrystalName,CompoundCode from mainTable where RefinementOutcome='2 - PANDDA model';") -# for item in sample_list: -# xtal=str(item[0]) - for xtal in sorted(samples_to_export): - self.Logfile.insert('%s: getting compound code from database' %xtal) - query=self.db.execute_statement("select CompoundCode from mainTable where CrystalName='%s';" %xtal) - compoundID=str(query[0][0]) - self.Logfile.insert('%s: compounds code = %s' %(xtal,compoundID)) -# compoundID=str(item[1]) - if os.path.isfile(os.path.join(self.initial_model_directory,xtal,xtal+'.free.mtz')): - if os.path.isfile(os.path.join(self.initial_model_directory,xtal,xtal+'-ensemble-model.pdb')): - self.Logfile.insert('running inital refinement on PANDDA model of '+xtal) - Serial=XChemRefine.GetSerial(self.initial_model_directory,xtal) - ####################################################### - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'cootOut')): - os.mkdir(os.path.join(self.initial_model_directory,xtal,'cootOut')) - # create folder for new refinement cycle - if os.path.isdir(os.path.join(self.initial_model_directory,xtal,'cootOut','Refine_'+str(Serial))): - os.chdir(os.path.join(self.initial_model_directory,xtal,'cootOut','Refine_'+str(Serial))) - try: - os.system('/bin/rm *-ensemble-model.pdb *restraints*') - except: - self.Logfile.error("Restraint files didn't exist to remove. Will try to continue") - else: - os.mkdir(os.path.join(self.initial_model_directory,xtal,'cootOut','Refine_'+str(Serial))) - os.chdir(os.path.join(self.initial_model_directory,xtal,'cootOut','Refine_'+str(Serial))) - Refine=XChemRefine.panddaRefine(self.initial_model_directory,xtal,compoundID,self.datasource) - os.symlink(os.path.join(self.initial_model_directory,xtal,xtal+'-ensemble-model.pdb'),xtal+'-ensemble-model.pdb') - Refine.RunQuickRefine(Serial,self.RefmacParams,self.external_software,self.xce_logfile,'pandda_refmac') - -# elif xtal in os.path.join(self.panddas_directory,'processed_datasets',xtal,'modelled_structures', -# '{}-pandda-model.pdb'.format(xtal)): -# self.Logfile.insert('{}: cannot start refinement because {}'.format(xtal,xtal) + -# ' does not have a modelled structure. Check whether you expect this dataset to ' + -# ' have a modelled structure, compare pandda.inspect and datasource,' -# ' then tell XCHEMBB ') - - elif xtal in samples_to_export and not os.path.isfile( - os.path.join(self.initial_model_directory, xtal, xtal + '.free.mtz')): - self.Logfile.error('%s: cannot start refinement because %s.free.mtz is missing in %s' % ( - xtal, xtal, os.path.join(self.initial_model_directory, xtal))) - else: - self.Logfile.insert('%s: nothing to refine' % (xtal)) - - def import_samples_into_datasouce(self,samples_to_export): - - # first make a note of all the datasets which were used in pandda directory - os.chdir(os.path.join(self.panddas_directory,'processed_datasets')) - for xtal in glob.glob('*'): - self.db.execute_statement("update mainTable set DimplePANDDAwasRun = 'True',DimplePANDDAreject = 'False',DimplePANDDApath='{0!s}' where CrystalName is '{1!s}'".format(self.panddas_directory, xtal)) - # do the same as before, but look for rejected datasets - - try: - os.chdir(os.path.join(self.panddas_directory,'rejected_datasets')) - for xtal in glob.glob('*'): - self.db.execute_statement("update mainTable set DimplePANDDAwasRun = 'True',DimplePANDDAreject = 'True',DimplePANDDApath='{0!s}',DimplePANDDAhit = 'False' where CrystalName is '{1!s}'".format(self.panddas_directory, xtal)) - except OSError: - pass - - site_list = [] - pandda_hit_list=[] - - with open(os.path.join(self.panddas_directory,'analyses','pandda_inspect_sites.csv'),'rb') as csv_import: - csv_dict = csv.DictReader(csv_import) - for i,line in enumerate(csv_dict): - site_index=line['site_idx'] - name=line['Name'].replace("'","") - comment=line['Comment'] - site_list.append([site_index,name,comment]) - - - progress_step=1 - for i,line in enumerate(open(os.path.join(self.panddas_directory,'analyses','pandda_inspect_events.csv'))): - n_lines=i - if n_lines != 0: - progress_step=100/float(n_lines) - else: - progress_step=0 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.Logfile.insert('reading '+os.path.join(self.panddas_directory,'analyses','pandda_inspect_events.csv')) - with open(os.path.join(self.panddas_directory,'analyses','pandda_inspect_events.csv'),'rb') as csv_import: - csv_dict = csv.DictReader(csv_import) - - for i,line in enumerate(csv_dict): - db_dict={} - sampleID=line['dtag'] - if sampleID not in samples_to_export: - self.Logfile.warning('%s: not to be exported; will not add to panddaTable...' %sampleID) - continue - if sampleID not in pandda_hit_list: - pandda_hit_list.append(sampleID) - site_index=line['site_idx'] - event_index=line['event_idx'] - self.Logfile.insert('reading {0!s} -> site {1!s} -> event {2!s}'.format(sampleID, site_index, event_index)) - - for entry in site_list: - if entry[0]==site_index: - site_name=entry[1] - site_comment=entry[2] - break - - # check if EVENT map exists in project directory - event_map='' - for file in glob.glob(os.path.join(self.initial_model_directory,sampleID,'*ccp4')): - filename=file[file.rfind('/')+1:] - if filename.startswith(sampleID+'-event_'+event_index) and filename.endswith('map.native.ccp4'): - event_map=file - self.Logfile.insert('found respective event maps in {0!s}: {1!s}'.format(self.initial_model_directory, event_map)) - break - - # initial pandda model and mtz file - pandda_model='' - for file in glob.glob(os.path.join(self.initial_model_directory,sampleID,'*pdb')): - filename=file[file.rfind('/')+1:] - if filename.endswith('-ensemble-model.pdb'): - pandda_model=file - if sampleID not in self.already_exported_models: - self.already_exported_models.append(sampleID) - break - inital_mtz='' - for file in glob.glob(os.path.join(self.initial_model_directory,sampleID,'*mtz')): - filename=file[file.rfind('/')+1:] - if filename.endswith('pandda-input.mtz'): - inital_mtz=file - break - - db_dict['CrystalName'] = sampleID - db_dict['PANDDApath'] = self.panddas_directory - db_dict['PANDDA_site_index'] = site_index - db_dict['PANDDA_site_name'] = site_name - db_dict['PANDDA_site_comment'] = site_comment - db_dict['PANDDA_site_event_index'] = event_index - db_dict['PANDDA_site_event_comment'] = line['Comment'].replace("'","") - db_dict['PANDDA_site_confidence'] = line['Ligand Confidence'] - db_dict['PANDDA_site_InspectConfidence'] = line['Ligand Confidence'] - db_dict['PANDDA_site_ligand_placed'] = line['Ligand Placed'] - db_dict['PANDDA_site_viewed'] = line['Viewed'] - db_dict['PANDDA_site_interesting'] = line['Interesting'] - db_dict['PANDDA_site_z_peak'] = line['z_peak'] - db_dict['PANDDA_site_x'] = line['x'] - db_dict['PANDDA_site_y'] = line['y'] - db_dict['PANDDA_site_z'] = line['z'] - db_dict['PANDDA_site_ligand_id'] = '' - db_dict['PANDDA_site_event_map'] = event_map - db_dict['PANDDA_site_initial_model'] = pandda_model - db_dict['PANDDA_site_initial_mtz'] = inital_mtz - db_dict['PANDDA_site_spider_plot'] = '' - - # find apo structures which were used - # XXX missing XXX - - self.db.update_insert_site_event_panddaTable(sampleID,db_dict) - - # this is necessary, otherwise RefinementOutcome will be reset for samples that are actually already in refinement - self.db.execute_statement("update panddaTable set RefinementOutcome = '2 - PANDDA model' where CrystalName is '{0!s}' and RefinementOutcome is null".format(sampleID)) - self.db.execute_statement("update mainTable set RefinementOutcome = '2 - PANDDA model' where CrystalName is '{0!s}' and (RefinementOutcome is null or RefinementOutcome is '1 - Analysis Pending')".format(sampleID)) - self.db.execute_statement("update mainTable set DimplePANDDAhit = 'True' where CrystalName is '{0!s}'".format(sampleID)) - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.Logfile.insert('done reading pandda_inspect_sites.csv') - - # finally find all samples which do not have a pandda hit - os.chdir(os.path.join(self.panddas_directory,'processed_datasets')) - self.Logfile.insert('check which datasets are not interesting') - # DimplePANDDAhit -# for xtal in glob.glob('*'): -# if xtal not in pandda_hit_list: -# self.Logfile.insert(xtal+': not in interesting_datasets; updating database...') -# self.db.execute_statement("update mainTable set DimplePANDDAhit = 'False' where CrystalName is '{0!s}'".format(xtal)) - - - def export_models(self): - - self.Logfile.insert('finding out which PanDDA models need to be exported') - - # first find which samples are in interesting datasets and have a model - # and determine the timestamp - fileModelsDict={} - queryModels='' - for model in glob.glob(os.path.join(self.panddas_directory,'processed_datasets','*','modelled_structures','*-pandda-model.pdb')): - sample=model[model.rfind('/')+1:].replace('-pandda-model.pdb','') - timestamp=datetime.fromtimestamp(os.path.getmtime(model)).strftime('%Y-%m-%d %H:%M:%S') - self.Logfile.insert(sample+'-pandda-model.pdb was created on '+str(timestamp)) - queryModels+="'"+sample+"'," - fileModelsDict[sample]=timestamp - - # now get these models from the database and compare the datestamps - # Note: only get the models that underwent some form of refinement, - # because only if the model was updated in pandda.inspect will it be exported and refined - dbModelsDict={} - if queryModels != '': - dbEntries=self.db.execute_statement("select CrystalName,DatePanDDAModelCreated from mainTable where CrystalName in ("+queryModels[:-1]+") and (RefinementOutcome like '3%' or RefinementOutcome like '4%' or RefinementOutcome like '5%')") - for item in dbEntries: - xtal=str(item[0]) - timestamp=str(item[1]) - dbModelsDict[xtal]=timestamp - self.Logfile.insert('PanDDA model for '+xtal+' is in database and was created on '+str(timestamp)) - - # compare timestamps and only export the ones where the timestamp of the file is newer than the one in the DB - samples_to_export={} - self.Logfile.insert('checking which PanDDA models were newly created or updated') - if self.which_models=='all': - self.Logfile.insert('Note: you chose to export ALL available PanDDA!') - - for sample in fileModelsDict: - if self.which_models=='all': - self.Logfile.insert('exporting '+sample) - samples_to_export[sample]=fileModelsDict[sample] - else: - if sample in dbModelsDict: - try: - difference=(datetime.strptime(fileModelsDict[sample],'%Y-%m-%d %H:%M:%S') - datetime.strptime(dbModelsDict[sample],'%Y-%m-%d %H:%M:%S') ) - if difference.seconds != 0: - self.Logfile.insert('exporting '+sample+' -> was already refined, but newer PanDDA model available') - samples_to_export[sample]=fileModelsDict[sample] - except ValueError: - # this will be raised if timestamp is not properly formatted; - # which will usually be the case when respective field in database is blank - # these are hopefully legacy cases which are from before this extensive check was introduced (13/01/2017) - advice = ( 'The pandda model of '+xtal+' was changed, but it was already refined! ' - 'This is most likely because this was done with an older version of XCE. ' - 'If you really want to export and refine this model, you need to open the database ' - 'with DBbroweser (sqlitebrowser.org); then change the RefinementOutcome field ' - 'of the respective sample to "2 - PANDDA model", save the database and repeat the export prodedure.' ) - self.Logfile.insert(advice) - else: - self.Logfile.insert('exporting '+sample+' -> first time to be exported and refined') - samples_to_export[sample]=fileModelsDict[sample] - - # update the DB: - # set timestamp to current timestamp of file and set RefinementOutcome to '2-pandda...' - - if samples_to_export != {}: - select_dir_string='' - select_dir_string_new_pannda=' ' - for sample in samples_to_export: - db_dict= {'RefinementOutcome': '2 - PANDDA model', 'DatePanDDAModelCreated': samples_to_export[sample]} - select_dir_string+="select_dir={0!s} ".format(sample) - select_dir_string_new_pannda+='{0!s} '.format(sample) - self.Logfile.insert('updating database for '+sample+' setting time model was created to '+db_dict['DatePanDDAModelCreated']+' and RefinementOutcome to '+db_dict['RefinementOutcome']) - self.db.update_data_source(sample,db_dict) - - - if os.path.isdir(os.path.join(self.panddas_directory,'rejected_datasets')): - - Cmds = ( - - 'pandda.export' - ' pandda_dir=%s' %self.panddas_directory+ - ' export_dir={0!s}'.format(self.initial_model_directory)+ - ' {0!s}'.format(select_dir_string)+ - ' export_ligands=False' - ' generate_occupancy_groupings=True\n' - ) - - else: - - Cmds = ( - 'source /dls/science/groups/i04-1/software/pandda-update/ccp4/ccp4-7.0/bin/ccp4.setup-sh\n' -# 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh')+'\n' - 'pandda.export' - ' pandda_dir=%s' %self.panddas_directory+ - ' export_dir={0!s}'.format(self.initial_model_directory)+ - ' {0!s}'.format(select_dir_string_new_pannda)+ - ' generate_restraints=True\n' - ) - - - - self.Logfile.insert('running pandda.export with the following settings:\n'+Cmds) - os.system(Cmds) - - return samples_to_export - - -class run_pandda_analyse(QtCore.QThread): - - def __init__(self,pandda_params,xce_logfile,datasource): - QtCore.QThread.__init__(self) - self.data_directory=pandda_params['data_dir'] - self.panddas_directory=pandda_params['out_dir'] - self.submit_mode=pandda_params['submit_mode'] - - self.pandda_analyse_data_table = pandda_params['pandda_table'] - self.nproc=pandda_params['nproc'] - self.min_build_datasets=pandda_params['min_build_datasets'] - self.pdb_style=pandda_params['pdb_style'] - self.mtz_style=pandda_params['mtz_style'] - self.sort_event=pandda_params['sort_event'] - self.number_of_datasets=pandda_params['N_datasets'] - self.max_new_datasets=pandda_params['max_new_datasets'] - self.grid_spacing=pandda_params['grid_spacing'] - self.reference_dir=pandda_params['reference_dir'] - self.filter_pdb=os.path.join(self.reference_dir,pandda_params['filter_pdb']) - self.wilson_scaling = pandda_params['perform_diffraction_data_scaling'] - self.Logfile=XChemLog.updateLog(xce_logfile) - self.datasource=datasource - self.db=XChemDB.data_source(datasource) - self.appendix=pandda_params['appendix'] - self.write_mean_maps=pandda_params['write_mean_map'] - self.calc_map_by = pandda_params['average_map'] - self.select_ground_state_model='' - projectDir = self.data_directory.replace('/*', '') - self.make_ligand_links='$CCP4/bin/ccp4-python %s %s %s\n' %(os.path.join(os.getenv('XChemExplorer_DIR'), - 'helpers', - 'make_ligand_links_after_pandda.py') - ,projectDir,self.panddas_directory) - self.use_remote = pandda_params['use_remote'] - self.remote_string = pandda_params['remote_string'] - - if self.appendix != '': - self.panddas_directory=os.path.join(self.reference_dir,'pandda_'+self.appendix) - if os.path.isdir(self.panddas_directory): - os.system('/bin/rm -fr %s' %self.panddas_directory) - os.mkdir(self.panddas_directory) - self.select_ground_state_model='$CCP4/bin/ccp4-python %s %s\n' %(os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','select_ground_state_dataset.py'),self.panddas_directory) - self.make_ligand_links='' - - def run(self): - - # print self.reference_dir - # print self.filter_pdb - - # how to run pandda.analyse on large datasets - # - # 1) Run the normal pandda command, with the new setting, e.g. - # pandda.analyse data_dirs=... max_new_datasets=500 - # This will do the analysis on the first 500 datasets and build the statistical maps - just as normal. - # - # 2) Run pandda with the same command: - # pandda.analyse data_dirs=... max_new_datasets=500 - # This will add 500 new datasets, and process them using the existing statistical maps - # (this will be quicker than the original analysis). It will then merge the results of the two analyses. - # - # 3) Repeat 2) until you don't add any "new" datasets. Then you can build the models as normal. - - - number_of_cyles=int(self.number_of_datasets)/int(self.max_new_datasets) - if int(self.number_of_datasets) % int(self.max_new_datasets) != 0: # modulo gives remainder after integer division - number_of_cyles+=1 - - if os.path.isfile(os.path.join(self.panddas_directory,'pandda.running')): - self.Logfile.insert('it looks as if a pandda.analyse job is currently running in: '+self.panddas_directory) - msg = ( 'there are three possibilities:\n' - '1.) choose another PANDDA directory\n' - '2.) - check if the job is really running either on the cluster (qstat) or on your local machine\n' - ' - if so, be patient and wait until the job has finished\n' - '3.) same as 2., but instead of waiting, kill the job and remove at least the pandda.running file\n' - ' (or all the contents in the directory if you want to start from scratch)\n' ) - self.Logfile.insert(msg) - return None - else: -# if os.getenv('SHELL') == '/bin/tcsh' or os.getenv('SHELL') == '/bin/csh': -# source_file=os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-csh\n') -# elif os.getenv('SHELL') == '/bin/bash' or self.use_remote: -# source_file='export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' -# source_file+='source %s\n' %os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh\n') -# else: -# source_file='' - # v1.2.1 - pandda.setup files should be obsolete now that pandda is part of ccp4 - source_file='source /dls/science/groups/i04-1/software/pandda_0.2.12/ccp4/ccp4-7.0/bin/ccp4.setup-sh\n' - source_file += 'export XChemExplorer_DIR="' + os.getenv('XChemExplorer_DIR') + '"\n' - - if os.path.isfile(self.filter_pdb + '.pdb'): - print('filter pdb located') - filter_pdb=' filter.pdb='+self.filter_pdb+'.pdb' - print('will use ' + filter_pdb + 'as a filter for pandda.analyse') - else: - if self.use_remote: - stat_command = self.remote_string.replace("qsub'", str('stat ' + self.filter_pdb + "'")) - output = subprocess.Popen(stat_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = output.communicate() - print out - if 'cannot stat' in out: - filter_pdb = '' - else: - filter_pdb = ' filter.pdb=' + self.filter_pdb + '.pdb' - - else: - filter_pdb='' - - os.chdir(self.panddas_directory) - - # note: copied latest pandda.setup-sh from XCE2 installation (08/08/2017) - - Cmds = ( - '#!'+os.getenv('SHELL')+'\n' + - '\n' + - source_file + - '\n' + 'module load pymol/1.8.2.0' + ' \n' + - 'cd ' + self.panddas_directory + '\n' + - '\n' - ) - - ignore = [] - char = [] - zmap = [] - - for i in range(0, self.pandda_analyse_data_table.rowCount()): - ignore_all_checkbox = self.pandda_analyse_data_table.cellWidget(i, 6) - ignore_characterisation_checkbox = self.pandda_analyse_data_table.cellWidget(i, 7) - ignore_zmap_checkbox = self.pandda_analyse_data_table.cellWidget(i, 8) - - if ignore_all_checkbox.isChecked(): - ignore.append(str(self.pandda_analyse_data_table.item(i, 0).text())) - if ignore_characterisation_checkbox.isChecked(): - char.append(str(self.pandda_analyse_data_table.item(i, 0).text())) - if ignore_zmap_checkbox.isChecked(): - zmap.append(str(self.pandda_analyse_data_table.item(i, 0).text())) - - print ignore - - def append_to_ignore_string(datasets_list, append_string): - if len(datasets_list)==0: - append_string = '' - for i in range(0, len(datasets_list)): - if i < len(datasets_list)-1: - append_string += str(datasets_list[i] + ',') - else: - append_string += str(datasets_list[i] +'"') - print(append_string) - return append_string - - ignore_string = 'ignore_datasets="' - ignore_string = append_to_ignore_string(ignore, ignore_string) - - char_string = 'exclude_from_characterisation="' - char_string = append_to_ignore_string(char, char_string) - - zmap_string = 'exclude_from_zmap_analysis="' - zmap_string = append_to_ignore_string(zmap, zmap_string) - - for i in range(number_of_cyles): - Cmds += ( - 'pandda.analyse '+ - ' data_dirs="'+self.data_directory.replace('/*','')+'/*"'+ - ' out_dir="'+self.panddas_directory+'"' - ' min_build_datasets='+self.min_build_datasets+ - ' max_new_datasets='+self.max_new_datasets+ - ' grid_spacing='+self.grid_spacing+ - ' cpus='+self.nproc+ - ' events.order_by='+self.sort_event+ - filter_pdb+ - ' pdb_style='+self.pdb_style+ - ' mtz_style='+self.mtz_style+ - ' lig_style=/compound/*.cif'+ - ' apply_b_factor_scaling='+self.wilson_scaling+ - ' write_average_map='+self.write_mean_maps + - ' average_map=' + self.calc_map_by + - ' ' + - ignore_string +' '+ - char_string +' '+ - zmap_string +' '+ - '\n' - ) - - Cmds += self.select_ground_state_model - Cmds += self.make_ligand_links - Cmds += '\n' - - data_dir_string = self.data_directory.replace('/*', '') - - Cmds += str( - 'find ' + data_dir_string + - '/*/compound -name "*.cif" | while read line; do echo ${line//"' + - data_dir_string + '"/"' + self.panddas_directory + - '/processed_datasets/"}| while read line2; do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; ' - 'done; done;') - - Cmds += '\n' - - - - Cmds += str( - 'find ' + data_dir_string + - '/*/compound -name "*.pdb" | while read line; do echo ${line//"' + - data_dir_string + '"/"' + self.panddas_directory + - '/processed_datasets/"}| while read line2; do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; ' - 'done; done;') - - self.Logfile.insert('running pandda.analyse with the following command:\n'+Cmds) - - - - f = open('pandda.sh','w') - f.write(Cmds) - f.close() - -# #>>> for testing -# self.submit_mode='local machine' - - if self.submit_mode=='local machine': - self.Logfile.insert('running PANDDA on local machine') - os.system('chmod +x pandda.sh') - os.system('./pandda.sh &') - elif self.use_remote: - # handles remote submission of pandda.analyse jobs - submission_string = self.remote_string.replace("qsub'", - str('cd ' + - self.panddas_directory + - '; ' + - "qsub -P labxchem -q medium.q -N pandda 5 -l exclusive,m_mem_free=100G pandda.sh'")) - os.system(submission_string) - self.Logfile.insert(str('running PANDDA remotely, using: ' + submission_string)) - else: - self.Logfile.insert('running PANDDA on cluster, using qsub...') - os.system('qsub -P labxchem -q medium.q -N pandda -l exclusive,m_mem_free=100G pandda.sh') - - self.emit(QtCore.SIGNAL('datasource_menu_reload_samples')) - - - -class giant_cluster_datasets(QtCore.QThread): - - def __init__(self,initial_model_directory,pandda_params,xce_logfile,datasource,): - QtCore.QThread.__init__(self) - self.panddas_directory=pandda_params['out_dir'] - self.pdb_style=pandda_params['pdb_style'] - self.mtz_style=pandda_params['mtz_style'] - self.Logfile=XChemLog.updateLog(xce_logfile) - self.initial_model_directory=initial_model_directory - self.db=XChemDB.data_source(datasource) - - - def run(self): - - self.emit(QtCore.SIGNAL('update_progress_bar'), 0) - - if self.pdb_style.replace(' ','') == '': - self.Logfile.insert('PDB style is not set in pandda.analyse!') - self.Logfile.insert('cannot start pandda.analyse') - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'PDB style is not set in pandda.analyse!') - return None - - if self.mtz_style.replace(' ','') == '': - self.Logfile.insert('MTZ style is not set in pandda.analyse!') - self.Logfile.insert('cannot start pandda.analyse') - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'MTZ style is not set in pandda.analyse!') - return None - - # 1.) prepare output directory - os.chdir(self.panddas_directory) - if os.path.isdir('cluster_analysis'): - self.Logfile.insert('removing old cluster_analysis directory in {0!s}'.format(self.panddas_directory)) - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'removing old cluster_analysis directory in {0!s}'.format(self.panddas_directory)) - os.system('/bin/rm -fr cluster_analysis 2> /dev/null') - self.Logfile.insert('creating cluster_analysis directory in {0!s}'.format(self.panddas_directory)) - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'creating cluster_analysis directory in {0!s}'.format(self.panddas_directory)) - os.mkdir('cluster_analysis') - self.emit(QtCore.SIGNAL('update_progress_bar'), 10) - - # 2.) go through project directory and make sure that all pdb files really exist - # broken links derail the giant.cluster_mtzs_and_pdbs script - self.Logfile.insert('cleaning up broken links of {0!s} and {1!s} in {2!s}'.format(self.pdb_style, self.mtz_style, self.initial_model_directory)) - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'cleaning up broken links of {0!s} and {1!s} in {2!s}'.format(self.pdb_style, self.mtz_style, self.initial_model_directory)) - os.chdir(self.initial_model_directory) - for xtal in glob.glob('*'): - if not os.path.isfile(os.path.join(xtal,self.pdb_style)): - self.Logfile.insert('missing {0!s} and {1!s} for {2!s}'.format(self.pdb_style, self.mtz_style, xtal)) - os.system('/bin/rm {0!s}/{1!s} 2> /dev/null'.format(xtal, self.pdb_style)) - os.system('/bin/rm {0!s}/{1!s} 2> /dev/null'.format(xtal, self.mtz_style)) - self.emit(QtCore.SIGNAL('update_progress_bar'), 20) - - # 3.) giant.cluster_mtzs_and_pdbs - self.Logfile.insert("running giant.cluster_mtzs_and_pdbs {0!s}/*/{1!s} pdb_regex='{2!s}/(.*)/{3!s}' out_dir='{4!s}/cluster_analysis'".format(self.initial_model_directory, self.pdb_style, self.initial_model_directory, self.pdb_style, self.panddas_directory)) - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'running giant.cluster_mtzs_and_pdbs') - - if os.getenv('SHELL') == '/bin/tcsh' or os.getenv('SHELL') == '/bin/csh': - source_file=os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-csh') - elif os.getenv('SHELL') == '/bin/bash': - source_file=os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh') - else: - source_file='' - - Cmds = ( - '#!'+os.getenv('SHELL')+'\n' - 'unset PYTHONPATH\n' - 'source '+source_file+'\n' - "giant.datasets.cluster %s/*/%s pdb_regex='%s/(.*)/%s' out_dir='%s/cluster_analysis'" %(self.initial_model_directory,self.pdb_style,self.initial_model_directory,self.pdb_style,self.panddas_directory) - ) - -# os.system("giant.cluster_mtzs_and_pdbs %s/*/%s pdb_regex='%s/(.*)/%s' out_dir='%s/cluster_analysis'" %(self.initial_model_directory,self.pdb_style,self.initial_model_directory,self.pdb_style,self.panddas_directory)) - os.system(Cmds) - self.emit(QtCore.SIGNAL('update_progress_bar'), 80) - - # 4.) analyse output - self.Logfile.insert('parsing {0!s}/cluster_analysis'.format(self.panddas_directory)) - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'parsing {0!s}/cluster_analysis'.format(self.panddas_directory)) - os.chdir('{0!s}/cluster_analysis'.format(self.panddas_directory)) - cluster_dict={} - for out_dir in sorted(glob.glob('*')): - if os.path.isdir(out_dir): - cluster_dict[out_dir]=[] - for folder in glob.glob(os.path.join(out_dir,'pdbs','*')): - xtal=folder[folder.rfind('/')+1:] - cluster_dict[out_dir].append(xtal) - self.emit(QtCore.SIGNAL('update_progress_bar'), 90) - - # 5.) update datasource - self.Logfile.insert('updating datasource with results from giant.cluster_mtzs_and_pdbs') - if cluster_dict != {}: - for key in cluster_dict: - for xtal in cluster_dict[key]: - db_dict= {'CrystalFormName': key} - self.db.update_data_source(xtal,db_dict) - - # 6.) finish - self.emit(QtCore.SIGNAL('update_progress_bar'), 100) - self.Logfile.insert('finished giant.cluster_mtzs_and_pdbs') - self.emit(QtCore.SIGNAL('datasource_menu_reload_samples')) - -class check_if_pandda_can_run: - - # reasons why pandda cannot be run - # - there is currently a job running in the pandda directory - # - min datasets available is too low - # - required input paramters are not complete - # - map amplitude and phase labels don't exist - - def __init__(self,pandda_params,xce_logfile,datasource): - self.data_directory=pandda_params['data_dir'] - self.panddas_directory=pandda_params['out_dir'] - self.min_build_datasets=pandda_params['min_build_datasets'] - self.pdb_style=pandda_params['pdb_style'] - self.mtz_style=pandda_params['mtz_style'] - self.input_dir_structure=pandda_params['pandda_dir_structure'] - self.problem_found=False - self.error_code=-1 - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(datasource) - - def number_of_available_datasets(self): - counter=0 - for file in glob.glob(os.path.join(self.input_dir_structure,self.pdb_style)): - if os.path.isfile(file): - counter+=1 - self.Logfile.insert('pandda.analyse: found {0!s} useable datasets'.format(counter)) - return counter - - def get_first_dataset_in_project_directory(self): - first_dataset='' - for file in glob.glob(os.path.join(self.input_dir_structure,self.pdb_style)): - if os.path.isfile(file): - first_dataset=file - break - return first_dataset - - def compare_number_of_atoms_in_reference_vs_all_datasets(self,refData,dataset_list): - mismatched_datasets=[] - pdbtools=XChemUtils.pdbtools(refData) - refPDB=refData[refData.rfind('/')+1:] - refPDBlist=pdbtools.get_init_pdb_as_list() - n_atom_ref=len(refPDBlist) - for n_datasets,dataset in enumerate(dataset_list): - if os.path.isfile(os.path.join(self.data_directory.replace('*',''),dataset,self.pdb_style)): - n_atom=len(pdbtools.get_pdb_as_list(os.path.join(self.data_directory.replace('*',''),dataset,self.pdb_style))) - if n_atom_ref == n_atom: - self.Logfile.insert('{0!s}: atoms in PDB file ({1!s}): {2!s}; atoms in Reference file: {3!s} ===> OK'.format(dataset, self.pdb_style, str(n_atom), str(n_atom_ref))) - if n_atom_ref != n_atom: - self.Logfile.insert('{0!s}: atoms in PDB file ({1!s}): {2!s}; atoms in Reference file: {3!s} ===> ERROR'.format(dataset, self.pdb_style, str(n_atom), str(n_atom_ref))) - mismatched_datasets.append(dataset) - return n_datasets,mismatched_datasets - - def get_datasets_which_fit_to_reference_file(self,ref,reference_directory,cluster_dict,allowed_unitcell_difference_percent): - refStructure=XChemUtils.pdbtools(os.path.join(reference_directory,ref+'.pdb')) - symmRef=refStructure.get_spg_number_from_pdb() - ucVolRef=refStructure.calc_unitcell_volume_from_pdb() - cluster_dict[ref]=[] - cluster_dict[ref].append(os.path.join(reference_directory,ref+'.pdb')) - for dataset in glob.glob(os.path.join(self.data_directory,self.pdb_style)): - datasetStructure=XChemUtils.pdbtools(dataset) - symmDataset=datasetStructure.get_spg_number_from_pdb() - ucVolDataset=datasetStructure.calc_unitcell_volume_from_pdb() - - if symmDataset == symmRef: - try: - difference=math.fabs(1-(float(ucVolRef)/float(ucVolDataset)))*100 - if difference < allowed_unitcell_difference_percent: - sampleID=dataset.replace('/'+self.pdb_style,'')[dataset.replace('/'+self.pdb_style,'').rfind('/')+1:] - cluster_dict[ref].append(sampleID) - except ZeroDivisionError: - continue - return cluster_dict - - def remove_dimple_files(self,dataset_list): - for n_datasets,dataset in enumerate(dataset_list): - db_dict={} - if os.path.isfile(os.path.join(self.data_directory.replace('*',''),dataset,self.pdb_style)): - os.system('/bin/rm '+os.path.join(self.data_directory.replace('*',''),dataset,self.pdb_style)) - self.Logfile.insert('{0!s}: removing {1!s}'.format(dataset, self.pdb_style)) - db_dict['DimplePathToPDB']='' - db_dict['DimpleRcryst']='' - db_dict['DimpleRfree']='' - db_dict['DimpleResolutionHigh']='' - db_dict['DimpleStatus']='pending' - if os.path.isfile(os.path.join(self.data_directory.replace('*',''),dataset,self.mtz_style)): - os.system('/bin/rm '+os.path.join(self.data_directory.replace('*',''),dataset,self.mtz_style)) - self.Logfile.insert('{0!s}: removing {1!s}'.format(dataset, self.mtz_style)) - db_dict['DimplePathToMTZ']='' - if db_dict != {}: - self.db.update_data_source(dataset,db_dict) - - - def analyse_pdb_style(self): - pdb_found=False - for file in glob.glob(os.path.join(self.data_directory,self.pdb_style)): - if os.path.isfile(file): - pdb_found=True - break - if not pdb_found: - self.error_code=1 - message=self.warning_messages() - return message - - def analyse_mtz_style(self): - mtz_found=False - for file in glob.glob(os.path.join(self.data_directory,self.mtz_style)): - if os.path.isfile(file): - mtz_found=True - break - if not mtz_found: - self.error_code=2 - message=self.warning_messages() - return message - - def analyse_min_build_dataset(self): - counter=0 - for file in glob.glob(os.path.join(self.data_directory,self.mtz_style)): - if os.path.isfile(file): - counter+=1 - if counter <= self.min_build_datasets: - self.error_code=3 - message=self.warning_messages() - return message - - - def warning_messages(self): - message='' - if self.error_code==1: - message='PDB file does not exist' - if self.error_code==2: - message='MTZ file does not exist' - if self.error_code==3: - message='Not enough datasets available' - - return message - - -class convert_all_event_maps_in_database(QtCore.QThread): - - def __init__(self,initial_model_directory,xce_logfile,datasource): - QtCore.QThread.__init__(self) - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.initial_model_directory=initial_model_directory - self.datasource=datasource - self.db=XChemDB.data_source(datasource) - - def run(self): - sqlite = ( - 'select' - ' CrystalName,' - ' PANDDA_site_event_map,' - ' PANDDA_site_ligand_resname,' - ' PANDDA_site_ligand_chain,' - ' PANDDA_site_ligand_sequence_number,' - ' PANDDA_site_ligand_altLoc ' - 'from panddaTable ' - 'where PANDDA_site_event_map not like "event%"' - ) - print sqlite - query=self.db.execute_statement(sqlite) - print query - progress_step=1 - if len(query) != 0: - progress_step=100/float(len(query)) - else: - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - for item in query: - print item - xtalID=str(item[0]) - event_map=str(item[1]) - resname=str(item[2]) - chainID=str(item[3]) - resseq=str(item[4]) - altLoc=str(item[5]) - - if os.path.isfile(os.path.join(self.initial_model_directory,xtalID,'refine.pdb')): - os.chdir(os.path.join(self.initial_model_directory,xtalID)) - self.Logfile.insert('extracting ligand ({0!s},{1!s},{2!s},{3!s}) from refine.pdb'.format(str(resname), str(chainID), str(resseq), str(altLoc))) - XChemUtils.pdbtools(os.path.join(self.initial_model_directory,xtalID,'refine.pdb')).save_specific_ligands_to_pdb(resname,chainID,resseq,altLoc) - if os.path.isfile('ligand_{0!s}_{1!s}_{2!s}_{3!s}.pdb'.format(str(resname), str(chainID), str(resseq), str(altLoc))): - ligand_pdb='ligand_{0!s}_{1!s}_{2!s}_{3!s}.pdb'.format(str(resname), str(chainID), str(resseq), str(altLoc)) - print os.path.join(self.initial_model_directory,xtalID,ligand_pdb) - else: - self.Logfile.insert('could not extract ligand; trying next...') - continue - else: - self.Logfile.insert('directory: '+os.path.join(self.initial_model_directory,xtalID)+' -> cannot find refine.pdb; trying next') - continue - - if os.path.isfile(os.path.join(self.initial_model_directory,xtalID,'refine.mtz')): - resolution=XChemUtils.mtztools(os.path.join(self.initial_model_directory,xtalID,'refine.mtz')).get_high_resolution_from_mtz() - else: - self.Logfile.insert('directory: '+os.path.join(self.initial_model_directory,xtalID)+' -> cannot find refine.mtz; trying next') - continue - - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'eventMap -> SF for '+event_map) - convert_event_map_to_SF(self.initial_model_directory,xtalID,event_map,ligand_pdb,self.xce_logfile,self.datasource,resolution).run() - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - - -class convert_event_map_to_SF: - def __init__(self,project_directory,xtalID,event_map,ligand_pdb,xce_logfile,db_file,resolution): - self.Logfile=XChemLog.updateLog(xce_logfile) - - self.event_map=event_map - if not os.path.isfile(self.event_map): - self.Logfile.insert('cannot find Event map: '+self.event_map) - self.Logfile.insert('cannot convert event_map to structure factors!') - return None - - self.project_directory=project_directory - self.xtalID=xtalID - self.event_map=event_map - self.ligand_pdb=ligand_pdb - self.event=event_map[event_map.rfind('/')+1:].replace('.map','').replace('.ccp4','') - self.db=XChemDB.data_source(db_file) - self.resolution=resolution - - def run(self): - os.chdir(os.path.join(self.project_directory,self.xtalID)) - - - # remove exisiting mtz file - if os.path.isfile(self.event+'.mtz'): - self.Logfile.insert('removing existing '+self.event+'.mtz') - os.system('/bin/rm '+self.event+'.mtz') - - # event maps generated with pandda v0.2 or higher have the same symmetry as the crystal - # but phenix.map_to_structure_facors only accepts maps in spg P1 - # therefore map is first expanded to full unit cell and spg of map then set tp p1 - # other conversion option like cinvfft give for whatever reason uninterpretable maps - self.convert_map_to_p1() - - # run phenix.map_to_structure_factors - self.run_phenix_map_to_structure_factors() - - self.remove_and_rename_column_labels() - - # check if output files exist - if not os.path.isfile('{0!s}.mtz'.format(self.event)): - self.Logfile.insert('cannot find {0!s}.mtz'.format(self.event)) - else: - self.Logfile.insert('conversion successful, {0!s}.mtz exists'.format(self.event)) - # update datasource with event_map_mtz information - self.update_database() - - - - def calculate_electron_density_map(self,mtzin): - missing_columns=False - column_dict=XChemUtils.mtztools(mtzin).get_all_columns_as_dict() - if 'FWT' in column_dict['F'] and 'PHWT' in column_dict['PHS']: - labin=' labin F1=FWT PHI=PHWT\n' - elif '2FOFCWT' in column_dict['F'] and 'PH2FOFCWT' in column_dict['PHS']: - labin=' labin F1=2FOFCWT PHI=PH2FOFCWT\n' - else: - missing_columns=True - - if not missing_columns: - os.chdir(os.path.join(self.project_directory,self.xtalID)) - cmd = ( - 'fft hklin '+mtzin+' mapout 2fofc.map << EOF\n' - +labin+ - 'EOF\n' - ) - self.Logfile.insert('calculating 2fofc map from '+mtzin) - os.system(cmd) - else: - self.Logfile.insert('cannot calculate 2fofc.map; missing map coefficients') - - def prepare_conversion_script(self): - - os.chdir(os.path.join(self.project_directory, self.xtalID)) - - # see also: - # http://www.phaser.cimr.cam.ac.uk/index.php/Using_Electron_Density_as_a_Model - - if os.getcwd().startswith('/dls'): - phenix_module='module_load_phenix\n' - else: - phenix_module='' - - cmd = ( - '#!'+os.getenv('SHELL')+'\n' - '\n' - +phenix_module+ - '\n' - 'pdbset XYZIN %s XYZOUT mask_ligand.pdb << eof\n' %self.ligand_pdb+ - ' SPACEGROUP {0!s}\n'.format(self.space_group)+ - ' CELL {0!s}\n'.format((' '.join(self.unit_cell)))+ - ' END\n' - 'eof\n' - '\n' - 'ncsmask XYZIN mask_ligand.pdb MSKOUT mask_ligand.msk << eof\n' - ' GRID %s\n' %(' '.join(self.gridElectronDensityMap))+ - ' RADIUS 10\n' - ' PEAK 1\n' - 'eof\n' - '\n' - 'mapmask MAPIN %s MAPOUT onecell_event_map.map << eof\n' %self.event_map+ - ' XYZLIM CELL\n' - 'eof\n' - '\n' - 'maprot MAPIN onecell_event_map.map MSKIN mask_ligand.msk WRKOUT masked_event_map.map << eof\n' - ' MODE FROM\n' - ' SYMMETRY WORK %s\n' %self.space_group_numberElectronDensityMap+ - ' AVERAGE\n' - ' ROTATE EULER 0 0 0\n' - ' TRANSLATE 0 0 0\n' - 'eof\n' - '\n' - 'mapmask MAPIN masked_event_map.map MAPOUT masked_event_map_fullcell.map << eof\n' - ' XYZLIM CELL\n' - ' PAD 0.0\n' - 'eof\n' - '\n' - 'sfall HKLOUT %s.mtz MAPIN masked_event_map_fullcell.map << eof\n' %self.event+ - ' LABOUT FC=FC_event PHIC=PHIC_event\n' - ' MODE SFCALC MAPIN\n' - ' RESOLUTION %s\n' %self.resolution+ - ' END\n' - ) - - self.Logfile.insert('preparing script for conversion of Event map to SF') - f = open('eventMap2sf.sh','w') - f.write(cmd) - f.close() - os.system('chmod +x eventMap2sf.sh') - - - def run_conversion_script(self): - self.Logfile.insert('running conversion script...') - os.system('./eventMap2sf.sh') - - def convert_map_to_p1(self): - self.Logfile.insert('running mapmask -> converting map to p1...') - cmd = ( '#!'+os.getenv('SHELL')+'\n' - '\n' - 'mapmask mapin %s mapout %s_p1.map << eof\n' %(self.event_map,self.event) + - 'xyzlin cell\n' - 'symmetry p1\n' ) - self.Logfile.insert('mapmask command:\n%s' %cmd) - os.system(cmd) - - def run_phenix_map_to_structure_factors(self): - if float(self.resolution) < 1.21: # program complains if resolution is 1.2 or higher - self.resolution='1.21' - self.Logfile.insert('running phenix.map_to_structure_factors {0!s}_p1.map d_min={1!s} output_file_name={2!s}_tmp.mtz'.format(self.event, self.resolution, self.event)) - os.system('phenix.map_to_structure_factors {0!s}_p1.map d_min={1!s} output_file_name={2!s}_tmp.mtz'.format(self.event, self.resolution, self.event)) - - def run_cinvfft(self,mtzin): - # mtzin is usually refine.mtz - self.Logfile.insert('running cinvfft -mapin {0!s} -mtzin {1!s} -mtzout {2!s}_tmp.mtz -colout event'.format(self.event_map, mtzin, self.event)) - os.system('cinvfft -mapin {0!s} -mtzin {1!s} -mtzout {2!s}_tmp.mtz -colout event'.format(self.event_map, mtzin, self.event)) - - - def remove_and_rename_column_labels(self): - - cmd = ( '#!'+os.getenv('SHELL')+'\n' - '\n' - 'cad hklin1 %s_tmp.mtz hklout %s.mtz << eof\n' %(self.event,self.event)+ - ' labin file_number 1 E1=F-obs E2=PHIF\n' - ' labout file_number 1 E1=F_ampl E2=PHIF\n' - 'eof\n' - '\n' ) - self.Logfile.insert('running CAD: new column labels F_ampl,PHIF') - os.system(cmd) - - def remove_and_rename_column_labels_after_cinvfft(self): - - cmd = ( '#!'+os.getenv('SHELL')+'\n' - '\n' - 'cad hklin1 %s_tmp.mtz hklout %s.mtz << eof\n' %(self.event,self.event)+ - ' labin file_number 1 E1=event.F_phi.F E2=event.F_phi.phi\n' - ' labout file_number 1 E1=F_ampl E2=PHIF\n' - 'eof\n' - '\n' ) - self.Logfile.insert('running CAD: renaming event.F_phi.F -> F_ampl and event.F_phi.phi -> PHIF') - os.system(cmd) - - - - def update_database(self): - sqlite = ( "update panddaTable set " - " PANDDA_site_event_map_mtz = '%s' " %os.path.join(self.project_directory,self.xtalID,self.event+'.mtz')+ - " where PANDDA_site_event_map is '{0!s}' ".format(self.event_map) - ) - self.db.execute_statement(sqlite) - self.Logfile.insert('updating data source: '+sqlite) - - def clean_output_directory(self): - os.system('/bin/rm mask_targetcell.pdb') - os.system('/bin/rm mask_targetcell.msk') - os.system('/bin/rm onecell.map') - os.system('/bin/rm masked_targetcell.map') - os.system('/bin/rm masked_fullcell.map') - os.system('/bin/rm eventMap2sf.sh') - os.system('/bin/rm '+self.ligand_pdb) - - -class run_pandda_inspect_at_home(QtCore.QThread): - - def __init__(self,panddaDir,xce_logfile): - QtCore.QThread.__init__(self) - self.panddaDir=panddaDir - self.Logfile=XChemLog.updateLog(xce_logfile) - - def run(self): - os.chdir(os.path.join(self.panddaDir,'processed_datasets')) - - progress_step=1 - if len(glob.glob('*')) != 0: - progress_step=100/float(len(glob.glob('*'))) - else: - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - - self.Logfile.insert('parsing '+self.panddaDir) - for xtal in sorted(glob.glob('*')): - for files in glob.glob(xtal+'/ligand_files/*'): - if os.path.islink(files): - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'replacing symlink for {0!s} with real file'.format(files)) - self.Logfile.insert('replacing symlink for {0!s} with real file'.format(files)) - os.system('cp --remove-destination {0!s} {1!s}/ligand_files'.format(os.path.realpath(files), xtal)) - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - XChemToolTips.run_pandda_inspect_at_home(self.panddaDir) - - -class convert_apo_structures_to_mmcif(QtCore.QThread): - - def __init__(self,panddaDir,xce_logfile): - QtCore.QThread.__init__(self) - self.panddaDir=panddaDir - self.Logfile=XChemLog.updateLog(xce_logfile) - - def sf_convert_environment(self): - if os.path.isdir('/dls'): - pdb_extract_init = 'source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n' - pdb_extract_init += '/dls/science/groups/i04-1/software/pdb-extract-prod/bin/sf_convert' - else: - pdb_extract_init = 'source ' + os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/setup.sh') + '\n' - pdb_extract_init += +os.path.join(os.getenv('XChemExplorer_DIR'), - 'pdb_extract/pdb-extract-prod/bin/sf_convert') - return pdb_extract_init - - - def run(self): - self.Logfile.insert('converting apo structures in pandda directory to mmcif files') - self.Logfile.insert('chanfing to '+self.panddaDir) - progress_step=1 - if len(glob.glob('*')) != 0: - progress_step=100/float(len(glob.glob(os.path.join(self.panddaDir,'processed_datasets','*')))) - else: - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - pdb_extract_init = self.sf_convert_environment() - - self.Logfile.insert('parsing '+self.panddaDir) - for dirs in glob.glob(os.path.join(self.panddaDir,'processed_datasets','*')): - xtal = dirs[dirs.rfind('/')+1:] - self.Logfile.insert('%s: converting %s to mmcif' %(xtal,xtal+'-pandda-input.mtz')) - if os.path.isfile(os.path.join(dirs,xtal+'-pandda-input.mtz')): - if os.path.isfile(os.path.join(dirs,xtal+'_sf.mmcif')): - self.Logfile.insert('%s: %s_sf.mmcif exists; skipping...' %(xtal,xtal)) - else: - os.chdir(dirs) - Cmd = (pdb_extract_init + - ' -o mmcif' - ' -sf %s' % xtal+'-pandda-input.mtz' + - ' -out {0!s}_sf.mmcif > {1!s}.sf_mmcif.log'.format(xtal, xtal)) - self.Logfile.insert('running command: '+Cmd) - os.system(Cmd) - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - - - - - - - - - -class check_number_of_modelled_ligands(QtCore.QThread): - - def __init__(self,project_directory,xce_logfile,db_file): - QtCore.QThread.__init__(self) - self.Logfile=XChemLog.updateLog(xce_logfile) - self.project_directory=project_directory - self.db=XChemDB.data_source(db_file) - self.errorDict={} - - def update_errorDict(self,xtal,message): - if xtal not in self.errorDict: - self.errorDict[xtal]=[] - self.errorDict[xtal].append(message) - - def insert_new_row_in_panddaTable(self,xtal,ligand,site,dbDict): - resname= site[0] - chain= site[1] - seqnum= site[2] - altLoc= site[3] - x_site= site[5][0] - y_site= site[5][1] - z_site= site[5][2] - - resnameSimilarSite= ligand[0] - chainSimilarSite= ligand[1] - seqnumSimilarSite= ligand[2] - - siteList=[] - for entry in dbDict[xtal]: - siteList.append(str(entry[0])) - if entry[4] == resnameSimilarSite and entry[5] == chainSimilarSite and entry[6] == seqnumSimilarSite: - eventMap= str(entry[7]) - eventMap_mtz= str(entry[8]) - initialPDB= str(entry[9]) - initialMTZ= str(entry[10]) - event_id= str(entry[12]) - PanDDApath= str(entry[13]) - - db_dict={ - 'PANDDA_site_index': str(int(max(siteList))+1), - 'PANDDApath': PanDDApath, - 'PANDDA_site_ligand_id': resname+'-'+chain+'-'+seqnum, - 'PANDDA_site_ligand_resname': resname, - 'PANDDA_site_ligand_chain': chain, - 'PANDDA_site_ligand_sequence_number': seqnum, - 'PANDDA_site_ligand_altLoc': 'D', - 'PANDDA_site_event_index': event_id, - 'PANDDA_site_event_map': eventMap, - 'PANDDA_site_event_map_mtz': eventMap_mtz, - 'PANDDA_site_initial_model': initialPDB, - 'PANDDA_site_initial_mtz': initialMTZ, - 'PANDDA_site_ligand_placed': 'True', - 'PANDDA_site_x': x_site, - 'PANDDA_site_y': y_site, - 'PANDDA_site_z': z_site } - - print xtal,db_dict - - - - - - def run(self): - - self.Logfile.insert('reading modelled ligands from panddaTable') - dbDict={} - - sqlite = ( "select " - " CrystalName," - " PANDDA_site_index," - " PANDDA_site_x," - " PANDDA_site_y," - " PANDDA_site_z," - " PANDDA_site_ligand_resname," - " PANDDA_site_ligand_chain," - " PANDDA_site_ligand_sequence_number," - " PANDDA_site_event_map," - " PANDDA_site_event_map_mtz," - " PANDDA_site_initial_model," - " PANDDA_site_initial_mtz," - " RefinementOutcome," - " PANDDA_site_event_index," - " PANDDApath " - "from panddaTable " ) - - - dbEntries=self.db.execute_statement(sqlite) - for item in dbEntries: - xtal= str(item[0]) - site= str(item[1]) - x= str(item[2]) - y= str(item[3]) - z= str(item[4]) - resname= str(item[5]) - chain= str(item[6]) - seqnum= str(item[7]) - eventMap= str(item[8]) - eventMap_mtz= str(item[9]) - initialPDB= str(item[10]) - initialMTZ= str(item[11]) - outcome= str(item[12]) - event= str(item[13]) - PanDDApath= str(item[14]) - - if xtal not in dbDict: - dbDict[xtal]=[] - dbDict[xtal].append([site,x,y,z,resname,chain,seqnum,eventMap,eventMap_mtz,initialPDB,initialMTZ,outcome,event,PanDDApath]) - - - os.chdir(self.project_directory) - - progress_step=1 - if len(glob.glob('*')) != 0: - progress_step=100/float(len(glob.glob('*'))) - else: - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - for xtal in sorted(glob.glob('*')): - if os.path.isfile(os.path.join(xtal,'refine.pdb')): - ligands=XChemUtils.pdbtools(os.path.join(xtal,'refine.pdb')).ligand_details_as_list() - self.Logfile.insert('{0!s}: found file refine.pdb'.format(xtal)) - if ligands: - if os.path.isdir(os.path.join(xtal,'xceTmp')): - os.system('/bin/rm -fr {0!s}'.format(os.path.join(xtal,'xceTmp'))) - os.mkdir(os.path.join(xtal,'xceTmp')) - else: - self.Logfile.warning('{0!s}: cannot find ligand molecule in refine.pdb; skipping...'.format(xtal)) - continue - - made_sym_copies=False - ligands_not_in_panddaTable=[] - for n,item in enumerate(ligands): - resnameLIG= item[0] - chainLIG= item[1] - seqnumLIG= item[2] - altLocLIG= item[3] - occupancyLig= item[4] - if altLocLIG.replace(' ','') == '': - self.Logfile.insert(xtal+': found a ligand not modelled with pandda.inspect -> {0!s} {1!s} {2!s}'.format(resnameLIG, chainLIG, seqnumLIG)) - residue_xyz = XChemUtils.pdbtools(os.path.join(xtal,'refine.pdb')).get_center_of_gravity_of_residue_ish(item[1],item[2]) - ligands[n].append(residue_xyz) - foundLigand=False - if xtal in dbDict: - for entry in dbDict[xtal]: - resnameTable=entry[4] - chainTable=entry[5] - seqnumTable=entry[6] - self.Logfile.insert('panddaTable: {0!s} {1!s} {2!s} {3!s}'.format(xtal, resnameTable, chainTable, seqnumTable)) - if resnameLIG == resnameTable and chainLIG == chainTable and seqnumLIG == seqnumTable: - self.Logfile.insert('{0!s}: found ligand in database -> {1!s} {2!s} {3!s}'.format(xtal, resnameTable, chainTable, seqnumTable)) - foundLigand=True - if not foundLigand: - self.Logfile.error('{0!s}: did NOT find ligand in database -> {1!s} {2!s} {3!s}'.format(xtal, resnameLIG, chainLIG, seqnumLIG)) - ligands_not_in_panddaTable.append([resnameLIG,chainLIG,seqnumLIG,altLocLIG,occupancyLig,residue_xyz]) - else: - self.Logfile.warning('ligand in PDB file, but dataset not listed in panddaTable: {0!s} -> {1!s} {2!s} {3!s}'.format(xtal, item[0], item[1], item[2])) - - for entry in ligands_not_in_panddaTable: - self.Logfile.error('{0!s}: refine.pdb contains a ligand that is not assigned in the panddaTable: {1!s} {2!s} {3!s} {4!s}'.format(xtal, entry[0], entry[1], entry[2], entry[3])) - - for site in ligands_not_in_panddaTable: - - for files in glob.glob(os.path.join(self.project_directory,xtal,'xceTmp','ligand_*_*.pdb')): - mol_xyz = XChemUtils.pdbtools(files).get_center_of_gravity_of_molecule_ish() - # now need to check if there is a unassigned entry in panddaTable that is close - for entry in dbDict[xtal]: - distance = XChemUtils.misc().calculate_distance_between_coordinates(mol_xyz[0], mol_xyz[1],mol_xyz[2],entry[1],entry[2], entry[3]) - self.Logfile.insert('{0!s}: {1!s} {2!s} {3!s} <---> {4!s} {5!s} {6!s}'.format(xtal, mol_xyz[0], mol_xyz[1], mol_xyz[2], entry[1], entry[2], entry[3])) - self.Logfile.insert('{0!s}: symm equivalent molecule: {1!s}'.format(xtal, files)) - self.Logfile.insert('{0!s}: distance: {1!s}'.format(xtal, str(distance))) - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - if self.errorDict != {}: - self.update_errorDict('General','The aforementioned PDB files were automatically changed by XCE!\nPlease check and refine them!!!') - self.emit(QtCore.SIGNAL('show_error_dict'), self.errorDict) - - - -class find_event_map_for_ligand(QtCore.QThread): - - def __init__(self,project_directory,xce_logfile): - QtCore.QThread.__init__(self) - self.Logfile=XChemLog.updateLog(xce_logfile) - self.project_directory=project_directory - - def run(self): - self.Logfile.insert('======== checking ligand CC in event maps ========') - for dirs in sorted(glob.glob(os.path.join(self.project_directory,'*'))): - xtal = dirs[dirs.rfind('/')+1:] - if os.path.isfile(os.path.join(dirs,'refine.pdb')) and \ - os.path.isfile(os.path.join(dirs,'refine.mtz')): - self.Logfile.insert('%s: found refine.pdb' %xtal) - os.chdir(dirs) - reso = XChemUtils.mtztools('refine.mtz').get_dmin() - ligList = XChemUtils.pdbtools('refine.pdb').save_residues_with_resname(dirs,'LIG') - self.Logfile.insert('%s: found %s ligands of type LIG in refine.pdb' %(xtal,str(len(ligList)))) - - for maps in glob.glob(os.path.join(dirs,'*event*.native.ccp4')): - self.expand_map_to_p1(maps) - self.convert_map_to_sf(maps.replace('.ccp4','.P1.ccp4'),reso) - - summary = '' - for lig in sorted(ligList): - for mtz in sorted(glob.glob(os.path.join(dirs,'*event*.native*P1.mtz'))): - self.get_lig_cc(mtz,lig) - cc = self.check_lig_cc(mtz.replace('.mtz', '_CC.log')) - summary += '%s: %s LIG CC = %s (%s)\n' %(xtal,lig,cc,mtz[mtz.rfind('/')+1:]) - self.Logfile.insert('\nsummary of CC analysis:\n======================:\n'+summary) - - def expand_map_to_p1(self,emap): - self.Logfile.insert('expanding map to P1: %s' %emap) - if os.path.isfile(emap.replace('.ccp4','.P1.ccp4')): - self.Logfile.warning('P1 map exists; skipping...') - return - cmd = ( 'mapmask MAPIN %s MAPOUT %s << eof\n' %(emap,emap.replace('.ccp4','.P1.ccp4'))+ - ' XYZLIM CELL\n' - ' PAD 0.0\n' - ' SYMMETRY 1\n' - 'eof\n' ) - os.system(cmd) - - def convert_map_to_sf(self,emap,reso): - self.Logfile.insert('converting ccp4 map to mtz with phenix.map_to_structure_factors: %s' %emap) - if os.path.isfile(emap.replace('.ccp4','.mtz')): - self.Logfile.warning('mtz file of event map exists; skipping...') - return - cmd = ( 'module load phenix\n' - 'phenix.map_to_structure_factors %s d_min=%s\n' %(emap,reso)+ - '/bin/mv map_to_structure_factors.mtz %s' %emap.replace('.ccp4', '.mtz') ) - os.system(cmd) - - def get_lig_cc(self,mtz,lig): - self.Logfile.insert('calculating CC for %s in %s' %(lig,mtz)) - if os.path.isfile(mtz.replace('.mtz', '_CC.log')): - self.Logfile.warning('logfile of CC analysis exists; skipping...') - return - cmd = ( 'module load phenix\n' - 'phenix.get_cc_mtz_pdb %s %s > %s' % (mtz, lig, mtz.replace('.mtz', '_CC.log')) ) - os.system(cmd) - - def check_lig_cc(self,log): - cc = 'n/a' - if os.path.isfile(log): - for line in open(log): - if line.startswith('local'): - cc = line.split()[len(line.split()) - 1] - else: - self.Logfile.error('logfile does not exist: %s' %log) - return cc diff --git a/lib/XChemPlots.py b/lib/XChemPlots.py deleted file mode 100755 index 6b8fca19..00000000 --- a/lib/XChemPlots.py +++ /dev/null @@ -1,75 +0,0 @@ -# last edited: 29/07/2016, 15:00 - -import os,sys - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -import XChemMain - -import matplotlib.pyplot as plt -from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas -import numpy as np - - -class summary_plot(object): - def __init__(self,datasource,overview_axes): - self.datasource=datasource - self.overview_axes=overview_axes - - def update_overview(self): - - db_dict=XChemMain.get_datasource_summary(self.datasource) - - category = ( 'Crystals mounted', - 'Data Collection', - 'Maps', - 'PANDDA', - 'Refinement', - 'Comp Chem' ) - - - N = len(category) - Success = np.array([ db_dict['nr_samples'], - db_dict['nr_data_collection_success'], - db_dict['nr_initial_maps_available'], - db_dict['nr_pandda_hits'], - 5, - 6 ]) - - Processed = np.array([ 0, - 0, - 0, - db_dict['nr_pandda_processed'], - 0, - 0 ]) - - Pending = np.array([ 0, - db_dict['nr_data_collection_pending'], - db_dict['nr_initial_maps_pending'], - db_dict['nr_pandda_pending'], - 2, - 1 ]) - - Failure = np.array([ db_dict['nr_samples_failed_to_mount'], - db_dict['nr_data_collection_failed'], - db_dict['nr_initial_maps_fail'], - db_dict['nr_pandda_reject'], - 2, - 3 ]) - - ind = np.arange(N) # the x locations for the groups - width = 0.35 # the width of the bars - - p0 = self.overview_axes.bar(ind, Success, width, color='g') - p1 = self.overview_axes.bar(ind, Processed, width, color='b', bottom=Success) - p2 = self.overview_axes.bar(ind, Pending, width, color='y', bottom=Success+Processed) - p3 = self.overview_axes.bar(ind, Failure, width, color='r', bottom=Pending+Success+Processed) - - - # add some text for labels, title and axes ticks - self.overview_axes.set_ylabel('N') - self.overview_axes.set_title('Overview') - self.overview_axes.set_xticks(ind + width) - self.overview_axes.set_xticklabels(category) - - self.overview_axes.legend((p0[0], p1[0], p2[0], p3[0]), ('Success', 'Processed', 'Pending', 'Failure')) diff --git a/lib/XChemProcess.py b/lib/XChemProcess.py deleted file mode 100755 index 1182230d..00000000 --- a/lib/XChemProcess.py +++ /dev/null @@ -1,222 +0,0 @@ -# last edited: 24/03/2017, 15:00 - -import os, sys, glob -from PyQt4 import QtGui, QtCore - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) -import XChemLog -import XChemDB - -class run_xia2(QtCore.QThread): - def __init__(self,initial_model_directory,run_dict,protocol,spg,ref,reso_limit,cc_half,xce_logfile,external_software,ccp4_scratch_directory,max_queue_jobs,database,overwrite): - QtCore.QThread.__init__(self) - self.initial_model_directory=initial_model_directory - self.run_dict=run_dict - self.protocol=protocol - self.spg=spg - self.ref=ref - self.reso_limit=reso_limit - self.cc_half=cc_half - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.external_software=external_software - self.ccp4_scratch_directory=ccp4_scratch_directory - self.max_queue_jobs=max_queue_jobs - self.database=database - self.db=XChemDB.data_source(database) - self.overwrite=overwrite - - def run(self): - os.chdir(os.path.join(self.initial_model_directory)) - # first create directories if they do not exist - - if not self.protocol: - self.Logfile.insert('please select data processing protocol first!') - return None - - for i,xtal in enumerate(self.run_dict): - - script='' - - if self.external_software['qsub']: - script+='#PBS -joe -N XCE_reprocess\n' - else: - script+='#!'+os.getenv('SHELL')+'\n' - - if 'bash' in os.getenv('SHELL'): - script += 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - elif 'csh' in os.getenv('SHELL'): - script += 'setenv XChemExplorer_DIR '+os.getenv('XChemExplorer_DIR')+'\n' - - if os.getcwd().startswith('/dls'): - script += 'module load ccp4\n' - script += 'module load XDS\n' -# script += 'module load phenix\n' - -# 2018-09-19 - removed this for Joe's test -# script += 'module load ccp4\n' -# script += 'module load XDS\n' -# script += 'module load ccp4 xia2\n' -# print 'hallo' - - if not self.spg: - spg_option='' - else: - spg_option='space_group='+str(self.spg[0]) - - if not self.ref: - ref_option='' - else: - ref_option='reference_reflection_file='+str(self.ref[0]) - - if not self.reso_limit: - reso_limit_option='' - else: - reso_limit_option='misigma='+str(self.reso_limit[0]) - - if not self.cc_half: - cc_half_option='' - else: - cc_half_option='cc_half='+str(self.cc_half[0]) - - - # first link diffraction images into directory - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): - os.mkdir(os.path.join(self.initial_model_directory,xtal)) - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'diffraction_images')): - os.mkdir(os.path.join(self.initial_model_directory,xtal,'diffraction_images')) - - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'processed')): - os.mkdir(os.path.join(self.initial_model_directory,xtal,'processed')) -# 2018-09-19 - disabled this for Joe's test -# if os.path.isfile(os.path.join(self.initial_model_directory,xtal,'processed','run_in_progress')): -# self.Logfile.insert('data processing is in progress; skipping...') -# continue - f = True - if f: - print 'hallo' - else: - if self.overwrite: - os.chdir(os.path.join(self.initial_model_directory,xtal,'diffraction_images')) - self.Logfile.insert('removing all links to diffraction images in '+os.path.join(self.initial_model_directory,xtal,'diffraction_images')) - os.system('/bin/rm -fr *') - os.chdir(os.path.join(self.initial_model_directory,xtal,'processed')) - self.Logfile.insert('removing all links to diffraction images in '+os.path.join(self.initial_model_directory,xtal,'processed')) - os.system('/bin/rm -fr *') - os.chdir(os.path.join(self.initial_model_directory,xtal,'processed')) -# 2018-09-19 - disabled this for Joe's test -# os.system('touch run_in_progress') - - for n,entry in enumerate(sorted(self.run_dict[xtal])): - newRun=1 - for runDir in sorted(glob.glob(os.path.join(self.initial_model_directory,xtal,'diffraction_images','run_*'))): - newRun=int(runDir[runDir.rfind('_')+1:])+1 - - os.mkdir(os.path.join(self.initial_model_directory,xtal,'diffraction_images','run_'+str(newRun))) - image_dir=os.path.join(self.initial_model_directory,xtal,'diffraction_images','run_'+str(newRun)) - os.chdir(os.path.join(self.initial_model_directory,xtal,'diffraction_images','run_'+str(newRun))) - os.system('ln -s '+os.path.join(entry[0],entry[1])+'* .') - - os.chdir(os.path.join(self.initial_model_directory,xtal,'processed')) - os.mkdir(os.path.join(self.initial_model_directory,xtal,'processed','run_'+str(newRun))) - - for pipeline in self.protocol: - script+='cd '+os.path.join(self.initial_model_directory,xtal,'processed','run_'+str(newRun),pipeline)+'\n' - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'processed','run_'+str(newRun),pipeline)): - os.mkdir(os.path.join(self.initial_model_directory,xtal,'processed','run_'+str(newRun),pipeline)) - - script+='$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_status_flag.py')+' {0!s} {1!s} {2!s} {3!s}\n'.format(self.database, xtal, 'DataProcessingStatus', 'running') - -# 2018-09-19 - changed this for Joe's test -# script+='$CCP4/bin/xia2 pipeline='+pipeline+' '+ref_option+' '+spg_option+' '+reso_limit_option+' '+cc_half_option+' '+image_dir+'\n' - script+='xia2 pipeline='+pipeline+' '+ref_option+' '+spg_option+' '+reso_limit_option+' '+cc_half_option+' '+image_dir+'\n' - - script+='$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_status_flag.py')+' {0!s} {1!s} {2!s} {3!s}\n'.format(self.database, xtal, 'DataProcessingStatus', 'finished') - script+='cd '+os.path.join(self.initial_model_directory,xtal,'processed')+'\n' - script+='/bin/rm run_in_progress\n' - - os.chdir(self.ccp4_scratch_directory) - f = open('xce_xia2_{0!s}.sh'.format(str(i+1)),'w') - f.write(script) - f.close() - os.system('chmod +x xce_xia2_{0!s}.sh'.format(str(i+1))) - db_dict= {'DataProcessingStatus': 'started'} - self.Logfile.insert('{0!s}: setting DataProcessingStatus flag to started'.format(xtal)) - self.db.update_data_source(xtal,db_dict) - - # submit job - self.Logfile.insert('created input scripts for '+str(n+1)+' in '+self.ccp4_scratch_directory) - os.chdir(self.ccp4_scratch_directory) - if os.getcwd().startswith('/dls'): - if self.external_software['qsub_array']: - Cmds = ( - '#PBS -joe -N xce_xia2_master\n' - './xce_xia2_$SGE_TASK_ID.sh\n' - ) - f = open('xia2_master.sh','w') - f.write(Cmds) - f.close() - self.Logfile.insert('submitting array job with maximal 100 jobs running on cluster') - self.Logfile.insert('using the following command:') - self.Logfile.insert('qsub -t 1:{0!s} -tc {1!s} xia2_master.sh'.format(str(i+1), self.max_queue_jobs)) - os.system('qsub -P labxchem -q medium.q -N xia2 -t 1:{0!s} -tc {1!s} xia2_master.sh'.format(str(i+1), self.max_queue_jobs)) - else: - self.Logfile.insert("cannot start ARRAY job: make sure that 'module load global/cluster' is in your .bashrc or .cshrc file") - elif self.external_software['qsub']: - self.Logfile.insert('submitting {0!s} individual jobs to cluster'.format((str(i+1)))) - self.Logfile.insert('WARNING: this could potentially lead to a crash...') - for n in range(i+1): - self.Logfile.insert('qsub xce_xia2_{0!s}.sh'.format((str(n+1)))) - os.system('qsub -q medium.q -N xia2 xce_xia2_{0!s}.sh'.format((str(n+1)))) - else: - self.Logfile.insert('running %s consecutive XIA2 jobs on your local machine') - for n in range(i+1): - self.Logfile.insert('starting xce_xia2_{0!s}.sh'.format((str(n+1)))) - os.system('./xce_xia2_{0!s}.sh'.format((str(n+1)))) - - -# if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): -# os.mkdir(os.path.join(self.initial_model_directory,xtal)) -# if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'autoprocessing')): -# os.mkdir(os.path.join(self.initial_model_directory,xtal,'autoprocessing')) -# -# -# -# -# if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc)): -# os.mkdir(os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc)) -# os.chdir(os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc)) -# os.system('touch dimple_run_in_progress') - - - - -# header='#!'+os.getenv('SHELL')+'\n' -# if external_software['qsub']: -# if not external_software['qsub_array']: -# header='#PBS -joe -N xce_acedrg\n' -# -# Cmds = ( -# header+ -# '\n' -# 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' -# '\n' -# 'source $XChemExplorer_DIR/setup-scripts/xce.setup-sh\n' -# '\n' -# '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','create_png_of_compound.py')+ -# ' "%s" %s %s %s\n' %(smiles,compoundID.replace(' ',''),sample,initial_model_directory)+ -# '\n' -# 'cd '+os.path.join(initial_model_directory,sample,'compound')+'\n' -# '\n' -# 'acedrg --res LIG -i "%s" -o %s\n' %(smiles,compoundID.replace(' ',''))+ -# '\n' -# 'cd '+os.path.join(initial_model_directory,sample)+'\n' -# '\n' -# 'ln -s compound/%s.cif .\n' %compoundID.replace(' ','')+ -# 'ln -s compound/%s.pdb .\n' %compoundID.replace(' ','')+ -# 'ln -s compound/%s.png .\n' %compoundID.replace(' ','')+ -# '\n' -# '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_for_new_cif_files.py')+ -# ' %s %s %s %s\n' %(os.path.join(database_directory,data_source_file),sample,initial_model_directory,compoundID.replace(' ','') )+ -# '\n' -# '/bin/rm compound/ACEDRG_IN_PROGRESS\n' diff --git a/lib/XChemRefine.py b/lib/XChemRefine.py deleted file mode 100755 index 36ee10ee..00000000 --- a/lib/XChemRefine.py +++ /dev/null @@ -1,1869 +0,0 @@ -# last edited: 08/08/2017, 15:00 - -import pygtk - -pygtk.require('2.0') -import gtk, pango - -import os -import glob -import sys -import getpass -import fileinput -import time -#sys.path.append(os.path.join(os.getenv('CCP4'),'lib/python2.7/site-packages')) -#import coot -#sys.path.append('/usr/local/coot/SoakProc/lib') -#import coot_utils_XChem - -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -import XChemLog -from XChemUtils import pdbtools - - -def GetSerial(ProjectPath,xtalID): - # check if there were already previous refinements - # if no: create a folder Refine_1 - # if yes: create a folder Refine_ - temp = [] - found = 0 - if os.path.isdir(os.path.join(ProjectPath,xtalID)): - for item in glob.glob(os.path.join(ProjectPath,xtalID,'*')): - if item.startswith(os.path.join(ProjectPath,xtalID,'Refine_')): - print int(item[item.rfind('_')+1:]) - temp.append(int(item[item.rfind('_')+1:])) - found = 1 - if found: - Serial = max(temp) + 1 - else: - Serial=1 - return Serial - - - -class RefineParams(object): - - def __init__(self,ProjectPath,xtalID,compoundID,datasource): - self.ProjectPath = ProjectPath - self.xtalID = xtalID - self.compoundID = compoundID - self.prefix = 'refine' - self.datasource=datasource - - - def RefmacRefinementParams(self,RefmacParams): - self.RefmacParams=RefmacParams - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_title("Refmac Parameters") - self.vbox = gtk.VBox() - - self.hbox1=gtk.HBox() - self.hbox1.add(gtk.Label('Refine')) - self.cb = gtk.combo_box_new_text() - self.cb.connect("changed", self.ChooseBfacRefinement) - for item in ['isotropic','anisotropic']: - self.cb.append_text(item) - if 'ISOT' in self.RefmacParams['BREF']: - self.cb.set_active(0) - if 'ANIS' in self.RefmacParams['BREF']: - self.cb.set_active(1) - self.hbox1.add(self.cb) - self.hbox1.add(gtk.Label('temperature factors')) - self.vbox.add(self.hbox1) - - self.hbox2=gtk.HBox() - self.hbox2.add(gtk.Label('Number of Cycles: ')) - self.Ncycles=gtk.Entry() - self.Ncycles.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.Ncycles.connect("key-release-event", self.on_key_release_Ncycles) - self.Ncycles.set_text(self.RefmacParams['NCYCLES']) - self.hbox2.add(self.Ncycles) - self.vbox.add(self.hbox2) - - self.hbox3=gtk.HBox() - self.hbox3.add(gtk.Label('MATRIX WEIGHT: ')) - self.MATRIX_WEIGHT=gtk.Entry() - self.MATRIX_WEIGHT.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.MATRIX_WEIGHT.connect("key-release-event", self.on_key_release_MATRIX_WEIGHT) - self.MATRIX_WEIGHT.set_text(self.RefmacParams['MATRIX_WEIGHT']) - self.hbox3.add(self.MATRIX_WEIGHT) - self.vbox.add(self.hbox3) - - self.TLS = gtk.CheckButton('TLS (find TLS groups with phenix.find_tls_groups)') - self.TLS.connect("toggled", self.TLSCallback) - if self.RefmacParams['TLS']=='refi tlsc 10\n': self.TLS.set_active(True) - self.vbox.pack_start(self.TLS,False) - - self.NCS = gtk.CheckButton('NCS (if applicable') - self.NCS.connect("toggled", self.NCSCallback) - if self.RefmacParams['NCS']=='NCSR LOCAL\n': self.NCS.set_active(True) - self.vbox.pack_start(self.NCS,False) - - self.TWIN = gtk.CheckButton('Twin?') - self.TWIN.connect("toggled", self.TWINCallback) - if self.RefmacParams['TWIN']=='TWIN\n': self.TWIN.set_active(True) - self.vbox.pack_start(self.TWIN,False) - - self.OKbutton = gtk.Button(label="OK") - self.OKbutton.connect("clicked",self.OK) - self.vbox.add(self.OKbutton) - - self.window.add(self.vbox) - self.window.show_all() - return self.RefmacParams - - - def TLSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TLS']='refi tlsc 10\n' - self.RefmacParams['TLSIN']='refmac.tls\n' - self.RefmacParams['TLSOUT']='out.tls\n' - self.RefmacParams['TLSADD']='TLSO ADDU\n' - else: - self.RefmacParams['TLS']='' - self.RefmacParams['TLSIN']='' - self.RefmacParams['TLSOUT']='' - self.RefmacParams['TLSADD']='' - return self.RefmacParams - - def NCSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['NCS']='NCSR LOCAL\n' - else: - self.RefmacParams['NCS']='' - return self.RefmacParams - - def ChooseBfacRefinement(self,widget): - if widget.get_active_text()=='isotropic': - self.RefmacParams['BREF']=' bref ISOT\n' - if widget.get_active_text()=='anisotropic': - self.RefmacParams['BREF']=' bref ANIS\n' - return self.RefmacParams - - def on_key_release_Ncycles(self, widget, event): - print widget.get_text() - self.RefmacParams['NCYCLES'] = widget.get_text() - return self.RefmacParams - - def on_key_release_MATRIX_WEIGHT(self, widget, event): - self.RefmacParams['MATRIX_WEIGHT'] = widget.get_text() - return self.RefmacParams - - def TWINCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TWIN']='TWIN\n' - else: - self.RefmacParams['TWIN']='' - return self.RefmacParams - - def OK(self,widget): - self.window.destroy() - - - def ParamsFromPreviousCycle(self,Serial): - - RefmacParams={ 'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': '' } - - if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - if line.startswith('refi tlsc'): - RefmacParams['TLS']=line - if line.startswith('TLSO'): - RefmacParams['TLSADD']=line - if line.startswith('NCSR LOCAL'): - RefmacParams['NCS']=line - if line.startswith(' bref '): - RefmacParams['BREF']=line - if line.startswith('ncyc'): - RefmacParams['Ncycles'] = line.split()[1] - if line.startswith('weight'): - RefmacParams['MATRIX_WEIGHT'] = line.split()[len(line.split())-1] - if line.startswith('TWIN'): - RefmacParams['TWIN']=line - elif os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'refmac.csh')): - for line in open(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'refmac.csh')): - if line.startswith('refi tlsc'): - RefmacParams['TLS']=line - if line.startswith('TLSO'): - RefmacParams['TLSADD']=line - if line.startswith('NCSR LOCAL'): - RefmacParams['NCS']=line - if line.startswith(' bref '): - RefmacParams['BREF']=line - if line.startswith('ncyc'): - RefmacParams['Ncycles'] = line.split()[1] - if line.startswith('weight'): - RefmacParams['MATRIX_WEIGHT'] = line.split()[len(line.split())-1] - if line.startswith('TWIN'): - RefmacParams['TWIN']=line - - return RefmacParams - - def GetRefinementHistory(self): -# RefinementHistory='' - RefinementCycle = [] - RcrystList=[] - RfreeList=[] - - found = False - for item in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if item.startswith(os.path.join(self.ProjectPath,self.xtalID,'Refine_')): - print item[item.rfind('_')+1:] - RefinementCycle.append(int(item[item.rfind('_')+1:])) - found = True - if found: - for cycle in sorted(RefinementCycle): -# for cycle in RefinementCycle: -# Rcryst=0 -# Rfree=0 -# LigandCC=0 - try: - found_Rcryst=False - found_Rfree=False - newestPDB = max(glob.iglob(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/refine_'+str(cycle)+'.pdb'), key=os.path.getctime) - for line in open(newestPDB): - if line.startswith('REMARK 3 R VALUE (WORKING + TEST SET) :'): - Rcryst = line.split()[9] - RcrystList.append(float(Rcryst)) - found_Rcryst=True - if line.startswith('REMARK 3 FREE R VALUE :'): - Rfree = line.split()[6] - RfreeList.append(float(Rfree)) - found_Rfree=True - if not found_Rcryst: - RcrystList.append(0) - if not found_Rfree: - RfreeList.append(0) -# if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# if line.startswith('| LIG'): LigandCC = line.split()[6] -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - except ValueError: - RcrystList.append(0) - RfreeList.append(0) -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - else: - RefinementCycle = [0] - RcrystList=[0] - RfreeList=[0] - print RefinementCycle,RcrystList,RfreeList - return(sorted(RefinementCycle),RcrystList,RfreeList) - - - - - -class Refine(object): - - def __init__(self,ProjectPath,xtalID,compoundID,datasource): - self.ProjectPath = ProjectPath - self.xtalID = xtalID - self.compoundID = compoundID - self.prefix = 'refine' - self.datasource=datasource - - def GetSerial(self): - # check if there were already previous refinements - # if no: create a folder Refine_1 - # if yes: create a folder Refine_ - temp = [] - found = 0 - if os.path.isdir(os.path.join(self.ProjectPath,self.xtalID)): - for item in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if item.startswith(os.path.join(self.ProjectPath,self.xtalID,'Refine_')): - print int(item[item.rfind('_')+1:]) - temp.append(int(item[item.rfind('_')+1:])) - found = 1 - if found: - Serial = max(temp) + 1 - else: - Serial=1 - return Serial - - - def make_covalent_link(self,covLinkAtomSpec,Logfile): - atom1 = covLinkAtomSpec[1][5] - atom2 = covLinkAtomSpec[2][5] - residue_1 = covLinkAtomSpec[3] - residue_2 = covLinkAtomSpec[4] - - bond_text = 'LINK: RES-NAME-1 %s FILE-1 %s_acedrg.cif ATOM-NAME-1 %s RES-NAME-2 %s ATOM-NAME-2 %s' %(residue_1,self.compoundID,atom1,residue_2,atom2) - os.chdir(os.path.join(self.ProjectPath,self.xtalID)) - f = open('covalent_bond.txt','w') - f.write(bond_text) - f.close() - - # seems somewhat unncessary, but acedrg does not like some certain descriptions generated by phenix.elbow - os.system('acedrg -c %s.cif -o %s_acedrg' %(self.compoundID,self.compoundID)) - - os.system('acedrg -L covalent_bond.txt -o %s' %self.compoundID) - - if os.path.isfile('%s_link.cif' %self.compoundID): - Logfile.insert('succefully created link file %s_link.cif' %self.compoundID) - os.system('/bin/rm %s.cif' %self.compoundID) - os.system('ln -s %s_link.cif %s.cif' %(self.compoundID,self.compoundID)) - else: - Logfile.error('could not create linkfile; please check logs in %s/%s' %(self.ProjectPath,self.xtalID)) - - - def RunRefmac(self,Serial,RefmacParams,external_software,xce_logfile,covLinkAtomSpec): - - if os.path.isfile(xce_logfile): Logfile=XChemLog.updateLog(xce_logfile) - Serial=str(Serial) - - if covLinkAtomSpec is not None: - self.make_covalent_link(covLinkAtomSpec,Logfile) - - # first check if refinement is ongoing and exit if yes - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'REFINEMENT_IN_PROGRESS')): -# coot.info_dialog('*** REFINEMENT IN PROGRESS ***') - Logfile.insert('cannot start new refinement for %s: *** REFINEMENT IN PROGRESS ***' %self.xtalID) - return None - - ####################################################### - # HKLIN & HKLOUT - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'.free.mtz')): - RefmacParams['HKLIN']='HKLIN '+os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'.free.mtz \\\n') -# elif os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz')): -# RefmacParams['HKLIN']='HKLIN '+os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz \\\n') - else: - Logfile.insert('%s: cannot find HKLIN for refinement; aborting...' %self.xtalID) - return None - RefmacParams['HKLOUT']='HKLOUT '+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refine_'+Serial+'.mtz \\\n') - - ####################################################### - # XYZIN & XYZOUT - RefmacParams['XYZIN']='XYZIN '+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'in.pdb \\\n') - RefmacParams['XYZOUT']='XYZOUT '+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refine_'+Serial+'.pdb \\\n') - - ####################################################### - # LIBIN & LIBOUT - found_cif=False - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.compoundID+'.cif')): - RefmacParams['LIBIN']='LIBIN '+self.ProjectPath+'/'+self.xtalID+'/'+self.compoundID+'.cif \\\n' - RefmacParams['LIBOUT']='LIBOUT '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'/refine_'+Serial+'.cif \\\n' - - ####################################################### - # TLSIN & TLSOUT - findTLS='\n' - TLSphenix='' - if RefmacParams['TLS'].startswith('refi'): - if external_software['phenix.find_tls_groups']: - findTLS=os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','phenix_find_TLS_groups.py')+' in.pdb\n' - RefmacParams['TLSIN']='TLSIN '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'/refmac.tls \\\n' - RefmacParams['TLSOUT']='TLSOUT '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'/refine.tls \\\n' - TLSphenix=' phenix.tls ' - else: - RefmacParams['TLS']='\n' - - print '==> XCE: assembling refmac.csh' - - ####################################################### - # we write 'REFINEMENT_IN_PROGRESS' immediately to avoid unncessary refiment - os.chdir(os.path.join(self.ProjectPath,self.xtalID)) - os.system('touch REFINEMENT_IN_PROGRESS') - - ####################################################### - # Database updates: - # no DB will be specified when a reference model is built and refined - refinementStatus='' - updateDB='' - if os.path.isfile(self.datasource): - refinementStatus='$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py %s %s %s %s\n' %(self.datasource,self.xtalID,'RefinementStatus','running') - updateDB = ( '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_after_refinement.py')+ - ' %s %s %s %s\n' %(self.datasource,self.xtalID,self.ProjectPath,os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial)) ) - - - ####################################################### - # clean up! - # and remove all files which will be re-created by current refinement cycle - os.system('/bin/rm refine.pdb refine.mtz refine.split.bound-state.pdb validation_summary.txt validate_ligands.txt 2fofc.map fofc.map refine_molprobity.log') - - if external_software['qsub']: - pbs_line='#PBS -joe -N XCE_refmac\n' - else: - pbs_line='\n' - - ####################################################### - # weight - if str(RefmacParams['MATRIX_WEIGHT']).lower() == 'auto': - weight='weight AUTO\n' - else: - weight='weight matrix '+str(RefmacParams['MATRIX_WEIGHT'])+'\n' - - ####################################################### - # PHENIX stuff (if working at DLS) - module_load='' - if os.getcwd().startswith('/dls'): - module_load='module load phenix\n' - - source ='' - if 'bash' in os.getenv('SHELL'): - source = ( - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','xce.setup-sh')+'\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh')+'\n' ) - elif 'csh' in os.getenv('SHELL'): - source = ( - 'setenv XChemExplorer_DIR '+os.getenv('XChemExplorer_DIR')+'\n' - '\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','xce.setup-csh')+'\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-csh')+'\n' ) - - - spider_plot='' - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-ensemble-model.pdb')): - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz')): - pdb_two=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-ensemble-model.pdb') - mtz_two=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz') - pdb_one=os.path.join(self.ProjectPath,self.xtalID,'Refine_'+str(Serial),'refine_'+str(Serial)+'.pdb') - mtz_one=os.path.join(self.ProjectPath,self.xtalID,'Refine_'+str(Serial),'refine_'+str(Serial)+'.mtz') - spider_plot = ( - 'cd ' + self.ProjectPath + '/' + self.xtalID + '/Refine_' + Serial + '\n' - '\n' -# 'giant.merge_conformations ' -# ' major=../refine.split.ground-state.pdb' -# ' minor=../refine.split.bound-state.pdb' -# ' reset_all_occupancies=False options.major_occupancy=1.0 options.minor_occupancy=1.0\n' - 'giant.score_model pdb1=%s mtz1=%s pdb2=%s mtz2=%s res_names=LIG,UNL,DRG,FRG\n' % (pdb_one, mtz_one, pdb_two, mtz_two) - ) - - - refmacCmds = ( - '#!'+os.getenv('SHELL')+'\n' - +pbs_line+ - '\n' - + module_load + - '\n' - +source+ - 'cd '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'\n' - '\n' - +refinementStatus+ - '\n' - +findTLS+ - 'refmac5 ' - +RefmacParams['HKLIN'] - +RefmacParams['HKLOUT'] - +RefmacParams['XYZIN'] - +RefmacParams['XYZOUT'] - +RefmacParams['LIBIN'] - +RefmacParams['LIBOUT'] - +RefmacParams['TLSIN'] - +RefmacParams['TLSOUT']+ - ' << EOF > refmac.log\n' - 'make -\n' - ' hydrogen ALL -\n' - ' hout NO -\n' - ' peptide NO -\n' - ' cispeptide YES -\n' - ' ssbridge YES -\n' - ' symmetry YES -\n' - ' sugar YES -\n' - ' connectivity NO -\n' - ' link NO\n' - +RefmacParams['NCS']+ - 'refi -\n' - ' type REST -\n' - ' resi MLKF -\n' - ' meth CGMAT -\n' - +RefmacParams['BREF'] - +RefmacParams['TLS'] - +RefmacParams['TWIN']+ - 'ncyc '+RefmacParams['NCYCLES']+'\n' - 'scal -\n' - ' type SIMP -\n' - ' LSSC -\n' - ' ANISO -\n' - ' EXPE\n' - +weight+ - 'solvent YES\n' - 'monitor MEDIUM -\n' - ' torsion 10.0 -\n' - ' distance 10.0 -\n' - ' angle 10.0 -\n' - ' plane 10.0 -\n' - ' chiral 10.0 -\n' - ' bfactor 10.0 -\n' - ' bsphere 10.0 -\n' - ' rbond 10.0 -\n' - ' ncsr 10.0\n' - 'labin FP=F SIGFP=SIGF FREE=FreeR_flag\n' - 'labout FC=FC FWT=FWT PHIC=PHIC PHWT=PHWT DELFWT=DELFWT PHDELWT=PHDELWT FOM=FOM\n' - +RefmacParams['TLSADD']+'\n' - 'DNAME '+self.xtalID+'\n' - 'END\n' - 'EOF\n' - '\n' - 'phenix.molprobity refine_%s.pdb refine_%s.mtz\n' %(Serial,Serial)+ - '/bin/mv molprobity.out refine_molprobity.log\n' - 'mmtbx.validate_ligands refine_%s.pdb refine_%s.mtz LIG > validate_ligands.txt\n' %(Serial,Serial)+ - 'cd '+self.ProjectPath+'/'+self.xtalID+'\n' - '#ln -s %s/%s/Refine_%s/refine_%s.pdb refine.pdb\n' %(self.ProjectPath,self.xtalID,Serial,Serial)+ - '#ln -s %s/%s/Refine_%s/refine_%s.mtz refine.mtz\n' %(self.ProjectPath,self.xtalID,Serial,Serial)+ - 'ln -s ./Refine_%s/refine_%s.pdb refine.pdb\n' %(Serial,Serial)+ - 'ln -s ./Refine_%s/refine_%s.mtz refine.mtz\n' %(Serial,Serial)+ - 'ln -s refine.pdb refine.split.bound-state.pdb\n' - '\n' - 'ln -s Refine_%s/validate_ligands.txt .\n' %Serial+ - 'ln -s Refine_%s/refine_molprobity.log .\n' %Serial+ - 'mmtbx.validation_summary refine.pdb > validation_summary.txt\n' - '\n' - 'fft hklin refine.mtz mapout 2fofc.map << EOF\n' - 'labin F1=FWT PHI=PHWT\n' - 'EOF\n' - '\n' - 'fft hklin refine.mtz mapout fofc.map << EOF\n' - 'labin F1=DELFWT PHI=PHDELWT\n' - 'EOF\n' - '\n' - +updateDB+ - '\n' - '/bin/rm %s/%s/REFINEMENT_IN_PROGRESS\n' %(self.ProjectPath,self.xtalID)+ - '\n' - 'cd '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'\n' - '\n' - +spider_plot+ - '\n' - ) - - if os.path.isfile(xce_logfile): Logfile.insert('writing refinement shell script to'+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refmac.csh')) - cmd = open(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refmac.csh'),'w') - cmd.write(refmacCmds) - cmd.close() - - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial)) -# os.system('ssh artemis "cd %s/%s/Refine_%s; qsub refmac.csh"' %(self.ProjectPath,self.xtalID,Serial)) - if os.path.isfile(xce_logfile): Logfile.insert('changing directory to %s' %(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial))) - if external_software['qsub_remote'] != '': - print os.getenv('LD_LIBRARY_PATH') - if os.path.isfile(xce_logfile): Logfile.insert('starting refinement on remote cluster') - remote_command=external_software['qsub_remote'].replace("qsub'",'cd %s; qsub' %os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial)) - os.system("%s -P labxchem -q medium.q refmac.csh'" %remote_command) - print '%s -P labxchem -q medium.q refmac.csh' %remote_command - - elif external_software['qsub'] and not os.uname()[1] == 'hestia': - Logfile.insert('starting refinement on cluster') - os.system("qsub -P labxchem -q medium.q refmac.csh") - - else: - os.system('chmod +x refmac.csh') - if os.path.isfile(xce_logfile): Logfile.insert('starting refinement on local machine') - os.system('./refmac.csh &') - - - - def RefinementParams(self,RefmacParams): - self.RefmacParams=RefmacParams - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_title("Refmac Parameters") - self.vbox = gtk.VBox() - - self.hbox1=gtk.HBox() - self.hbox1.add(gtk.Label('Refine')) - self.cb = gtk.combo_box_new_text() - self.cb.connect("changed", self.ChooseBfacRefinement) - for item in ['isotropic','anisotropic']: - self.cb.append_text(item) - if 'ISOT' in self.RefmacParams['BREF']: - self.cb.set_active(0) - if 'ANIS' in self.RefmacParams['BREF']: - self.cb.set_active(1) - self.hbox1.add(self.cb) - self.hbox1.add(gtk.Label('temperature factors')) - self.vbox.add(self.hbox1) - - self.hbox2=gtk.HBox() - self.hbox2.add(gtk.Label('Number of Cycles: ')) - self.Ncycles=gtk.Entry() - self.Ncycles.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.Ncycles.connect("key-release-event", self.on_key_release_Ncycles) - self.Ncycles.set_text(self.RefmacParams['NCYCLES']) - self.hbox2.add(self.Ncycles) - self.vbox.add(self.hbox2) - - self.hbox3=gtk.HBox() - self.hbox3.add(gtk.Label('MATRIX WEIGHT: ')) - self.MATRIX_WEIGHT=gtk.Entry() - self.MATRIX_WEIGHT.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.MATRIX_WEIGHT.connect("key-release-event", self.on_key_release_MATRIX_WEIGHT) - self.MATRIX_WEIGHT.set_text(self.RefmacParams['MATRIX_WEIGHT']) - self.hbox3.add(self.MATRIX_WEIGHT) - self.vbox.add(self.hbox3) - - self.TLS = gtk.CheckButton('TLS (find TLS groups with phenix.find_tls_groups)') - self.TLS.connect("toggled", self.TLSCallback) - if self.RefmacParams['TLS']=='refi tlsc 10\n': self.TLS.set_active(True) - self.vbox.pack_start(self.TLS,False) - - self.NCS = gtk.CheckButton('NCS (if applicable') - self.NCS.connect("toggled", self.NCSCallback) - if self.RefmacParams['NCS']=='NCSR LOCAL\n': self.NCS.set_active(True) - self.vbox.pack_start(self.NCS,False) - - self.TWIN = gtk.CheckButton('Twin?') - self.TWIN.connect("toggled", self.TWINCallback) - if self.RefmacParams['TWIN']=='TWIN\n': self.TWIN.set_active(True) - self.vbox.pack_start(self.TWIN,False) - - self.OKbutton = gtk.Button(label="OK") - self.OKbutton.connect("clicked",self.OK) - self.vbox.add(self.OKbutton) - - self.window.add(self.vbox) - self.window.show_all() - return self.RefmacParams - - - def TLSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TLS']='refi tlsc 10\n' - self.RefmacParams['TLSIN']='refmac.tls\n' - self.RefmacParams['TLSOUT']='out.tls\n' - self.RefmacParams['TLSADD']='TLSO ADDU\n' - else: - self.RefmacParams['TLS']='' - self.RefmacParams['TLSIN']='' - self.RefmacParams['TLSOUT']='' - self.RefmacParams['TLSADD']='' - return self.RefmacParams - - def NCSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['NCS']='NCSR LOCAL\n' - else: - self.RefmacParams['NCS']='' - return self.RefmacParams - - def ChooseBfacRefinement(self,widget): - if widget.get_active_text()=='isotropic': - self.RefmacParams['BREF']=' bref ISOT\n' - if widget.get_active_text()=='anisotropic': - self.RefmacParams['BREF']=' bref ANIS\n' - return self.RefmacParams - - def on_key_release_Ncycles(self, widget, event): - print widget.get_text() - self.RefmacParams['NCYCLES'] = widget.get_text() - return self.RefmacParams - - def on_key_release_MATRIX_WEIGHT(self, widget, event): - self.RefmacParams['MATRIX_WEIGHT'] = widget.get_text() - return self.RefmacParams - - def TWINCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TWIN']='TWIN\n' - else: - self.RefmacParams['TWIN']='' - return self.RefmacParams - - def OK(self,widget): - self.window.destroy() - - - def ParamsFromPreviousCycle(self,Serial): - - RefmacParams={ 'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': '' } - - if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - if line.startswith('refi tlsc'): - RefmacParams['TLS']=line - if line.startswith('TLSO'): - RefmacParams['TLSADD']=line - if line.startswith('NCSR LOCAL'): - RefmacParams['NCS']=line - if line.startswith(' bref '): - RefmacParams['BREF']=line - if line.startswith('ncyc'): - RefmacParams['Ncycles'] = line.split()[1] - if line.startswith('weight'): - RefmacParams['MATRIX_WEIGHT'] = line.split()[len(line.split())-1] - if line.startswith('TWIN'): - RefmacParams['TWIN']=line - elif os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'multi-state-restraints.refmac.params')): - for line in open(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'multi-state-restraints.refmac.params')): - if 'refi tlsc' in line: - RefmacParams['TLS']=line - if 'TLSO' in line: - RefmacParams['TLSADD']=line - if 'NCSR LOCAL' in line: - RefmacParams['NCS']=line - if 'bref' in line: - RefmacParams['BREF']=line - if 'ncyc' in line: - RefmacParams['Ncycles'] = line.split()[1] - if 'weight' in line: - RefmacParams['MATRIX_WEIGHT'] = line.split()[len(line.split())-1] - if 'TWIN' in line: - RefmacParams['TWIN']=line - - return RefmacParams - - def GetRefinementHistory(self): -# RefinementHistory='' - RefinementCycle = [] - RcrystList=[] - RfreeList=[] - - found = False - for item in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if item.startswith(os.path.join(self.ProjectPath,self.xtalID,'Refine_')): - print item[item.rfind('_')+1:] - RefinementCycle.append(int(item[item.rfind('_')+1:])) - found = True - if found: - for cycle in sorted(RefinementCycle): -# for cycle in RefinementCycle: -# Rcryst=0 -# Rfree=0 -# LigandCC=0 - try: - found_Rcryst=False - found_Rfree=False - newestPDB = max(glob.iglob(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/refine_'+str(cycle)+'.pdb'), key=os.path.getctime) - for line in open(newestPDB): - if line.startswith('REMARK 3 R VALUE (WORKING + TEST SET) :'): - Rcryst = line.split()[9] - RcrystList.append(float(Rcryst)) - found_Rcryst=True - if line.startswith('REMARK 3 FREE R VALUE :'): - Rfree = line.split()[6] - RfreeList.append(float(Rfree)) - found_Rfree=True - if not found_Rcryst: - RcrystList.append(0) - if not found_Rfree: - RfreeList.append(0) -# if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# if line.startswith('| LIG'): LigandCC = line.split()[6] -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - except ValueError: - RcrystList.append(0) - RfreeList.append(0) -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - else: - RefinementCycle = [0] - RcrystList=[0] - RfreeList=[0] - print RefinementCycle,RcrystList,RfreeList - return(sorted(RefinementCycle),RcrystList,RfreeList) - - - - -class panddaRefine(object): - - def __init__(self,ProjectPath,xtalID,compoundID,datasource): - self.ProjectPath = ProjectPath - self.xtalID = xtalID - self.compoundID = compoundID - self.prefix = 'refine' - self.datasource=datasource - - def RunQuickRefine(self,Serial,RefmacParams,external_software,xce_logfile,refinementProtocol): - Logfile=XChemLog.updateLog(xce_logfile) - Logfile.insert('preparing files for giant.quick_refine') - # panddaSerial because giant.quick_refine writes Refine_0001 instead of Refine_1 - panddaSerial=(4-len(str(Serial)))*'0'+str(Serial) - - make_all_links = True - add_links_line = '' - - # first check if refinement is ongoing and exit if yes - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'REFINEMENT_IN_PROGRESS')): -# coot.info_dialog('*** REFINEMENT IN PROGRESS ***') - Logfile.insert('cannot start new refinement for %s: *** REFINEMENT IN PROGRESS ***' %self.xtalID) - return None - - ####################################################### - # HKLIN & HKLOUT - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'.free.mtz')): - RefmacParams['HKLIN']=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'.free.mtz') - elif os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz')): - RefmacParams['HKLIN']=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz') - else: - Logfile.insert('%s: cannot find HKLIN for refinement; aborting...' %self.xtalID) - return None - - ####################################################### - # LIBIN & LIBOUT - found_cif=False - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.compoundID+'.cif')): - found_cif=True - RefmacParams['LIBIN']=os.path.join(self.ProjectPath,self.xtalID,self.compoundID+'.cif') - if not found_cif: - # this should actually not be necessary, but the following scenario can happen: - # if a new data source is created from a file system, but smiles and compoundID where not updated; - # so the ligand may still be in the structure, but since the compoundID is unknown to the datasource, - # its restraints won't be read in and refmac will fail - for file in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if file.endswith('.cif'): - RefmacParams['LIBIN']=file - break - - ####################################################### - # giant_merge_conformations - Logfile.insert('trying to merge modified bound state with ground state') - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),self.xtalID+'-ensemble-model.pdb')): - Logfile.insert('seems to be an initial refinement after pandda.export, no need to merge the conformations') - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - Logfile.insert('running giant.make_restraints %s:' %self.xtalID+'-ensemble-model.pdb') -# os.system('giant.make_restraints %s' %self.xtalID+'-ensemble-model.pdb') - cmd = ( - 'export XChemExplorer_DIR="%s"\n' %os.getenv('XChemExplorer_DIR')+ - 'source %s\n' %os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh\n') + - 'giant.make_restraints %s-ensemble-model.pdb' %self.xtalID - ) - Logfile.insert(cmd+'\n') - os.system(cmd) - elif os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'refine.split.ground-state.pdb')): - Logfile.insert('found model of ground state: '+os.path.join(self.ProjectPath,self.xtalID,'refine.split.ground-state.pdb')) - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'refine.modified.pdb')): - Logfile.insert('found model of modified bound state') - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - ground_state=os.path.join(self.ProjectPath,self.xtalID,'refine.split.ground-state.pdb') - bound_state='refine.modified.pdb' - Logfile.insert('running giant.merge_conformations major=%s minor=%s' %(ground_state,bound_state)) - if os.getcwd().startswith('/dls'): - cmd = ( - 'export XChemExplorer_DIR="%s"\n' %os.getenv('XChemExplorer_DIR')+ - 'source %s\n' %os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh\n') + - 'giant.merge_conformations major=%s minor=%s reset_all_occupancies=False options.major_occupancy=1.0 options.minor_occupancy=1.0' %(ground_state,bound_state) - ) - else: - cmd = ( - 'giant.merge_conformations major=%s minor=%s reset_all_occupancies=False options.major_occupancy=1.0 options.minor_occupancy=1.0' %(ground_state,bound_state) - ) - Logfile.insert(cmd+'\n') - os.system(cmd) - else: - Logfile.error('cannot find modified version of bound state in %s' %os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - return None - else: - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'refine.modified.pdb')): - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - Logfile.warning('%s: ground-state model does not exist, but refine.modified.pdb does exist' %self.xtalID) - Logfile.warning('This may be a case where there are no differences between bound and ground state') - Logfile.warning('creating symbolic link: ln -s refine.modified.pdb %s-ensemble-model.pdb' %self.xtalID) - os.system('ln -s refine.modified.pdb %s-ensemble-model.pdb' %self.xtalID) - # note: after first cycle of refinement, REFMAC will remove alternate conformer from the ligand - # i.e. need to link refine.pdb to refine.split.bound-state.pdb - make_all_links = False - add_links_line = 'ln -s refine.pdb refine.split.bound-state.pdb' - Logfile.insert('trying to continue with refinement') - else: - Logfile.error('cannot find any suitable PDB file for refinement, aborting...') - return None - - - ####################################################### - # checking if input PDB files are present - Logfile.insert('checking if input PDB files for REFMAC are present') - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),self.xtalID+'-ensemble-model.pdb')): - RefmacParams['XYZIN']=os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),self.xtalID+'-ensemble-model.pdb') - elif os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'multi-state-model.pdb')): - RefmacParams['XYZIN']=os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'multi-state-model.pdb') - else: - Logfile.error('cannot find multi-state-model.pdb in %s; aborting...' %os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - return None - - - ####################################################### - # checking if multi-state-restraints.refmac.params file is present - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'multi-state-restraints.refmac.params')): - # add REFMAC keywords to multi-state-restraints.refmac.params - with open('multi-state-restraints.refmac.params','a') as refmacParams: - refmacParams.write(RefmacParams['BREF']+'\n') - refmacParams.write(RefmacParams['TLS']+'\n') - refmacParams.write(RefmacParams['TWIN']+'\n') - refmacParams.write('ncyc '+RefmacParams['NCYCLES']+'\n') - if str(RefmacParams['MATRIX_WEIGHT']).lower() == 'auto': - refmacParams.write('weight AUTO' + '\n') - else: - refmacParams.write('weight matrix '+str(RefmacParams['MATRIX_WEIGHT'])+'\n') - refmacParams.write(RefmacParams['TLSADD']+'\n') - else: - Logfile.warning('cannot find multi-state-restraints.refmac.params in %s!' %os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - try: - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - Logfile.insert('checking if %s-ensemble-model.pdb contains residue of type LIG, DRG, FRG, UNK or UNL' %self.xtalID) - knowLigandIDs = ['LIG', 'DRG', 'FRG', 'UNK', 'UNL'] - ligandsInFile = pdbtools(self.xtalID+'-ensemble-model.pdb').find_ligands() - found_lig = False - for lig in ligandsInFile: - if lig[0] in knowLigandIDs: - Logfile.insert('found ligand of type: ' + lig[0]) - found_lig = True - if found_lig: - Logfile.warning('giant.make_restraints was not able to create multi-state-restraints.refmac.params. ' + - 'Something may have gone wrong, but it could be that ligand binding did not lead to ' + - 'displacement of water molecules or rearrangement of protein side-chains. ' + - 'Hence, there is no difference between the bound-state and the ground-state. ' + - 'We will create an empty multi-state-restraints.refmac.params which may contain ' + - 'additional REFMAC keywords and otherwise try to continue with refinement') - os.system('touch multi-state-restraints.refmac.params') - else: - Logfile.error('%s-ensemble-model.pdb does not contain any modelled ligand; aborting refinement' %self.xtalID) - return None - except OSError: - Logfile.error('directory does not exisit: %s' %os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - Logfile.error('aborting refinement...') - return None - - ####################################################### - # we write 'REFINEMENT_IN_PROGRESS' immediately to avoid unncessary refinement - os.chdir(os.path.join(self.ProjectPath,self.xtalID)) - os.system('touch REFINEMENT_IN_PROGRESS') - - ####################################################### - # clean up! - # and remove all files which will be re-created by current refinement cycle - os.chdir(os.path.join(self.ProjectPath,self.xtalID)) - files_to_remove = ( 'refine.pdb ' - 'refine.mtz ' - 'refine.split.bound-state.pdb ' - 'refine.split.ground-state.pdb ' - 'validation_summary.txt ' - 'validate_ligands.txt ' - '2fofc.map ' - 'fofc.map ' - 'refine_molprobity.log' ) - os.system('/bin/rm %s' %files_to_remove) - - if external_software['qsub']: - pbs_line='#PBS -joe -N XCE_refmac\n' - else: - pbs_line='\n' - - ####################################################### - # PANDDA validation @ spider plot - spider_plot='' - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-ensemble-model.pdb')): - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz')): - pdb_two=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-ensemble-model.pdb') - mtz_two=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz') - pdb_one=os.path.join(self.ProjectPath,self.xtalID,'Refine_'+str(panddaSerial),'refine_'+str(Serial)+'.pdb') - mtz_one=os.path.join(self.ProjectPath,self.xtalID,'Refine_'+str(panddaSerial),'refine_'+str(Serial)+'.mtz') - spider_plot+='giant.score_model pdb1=%s mtz1=%s pdb2=%s mtz2=%s res_names=LIG,UNL,DRG,FRG\n' %(pdb_one,mtz_one,pdb_two,mtz_two) - - ####################################################### - # PHENIX stuff (if working at DLS) - module_load='' - if os.getcwd().startswith('/dls'): - module_load='module load phenix\n' - - # 2017-07-20: for the time being this will explicitly source pandda since version 0.2 really only works at DLS - source ='' - if 'bash' in os.getenv('SHELL'): - source = ( - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'source %s\n' %os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh\n') - ) - elif 'csh' in os.getenv('SHELL'): - source = ( - 'setenv XChemExplorer_DIR '+os.getenv('XChemExplorer_DIR')+'\n' - '\n' - 'source %s\n' %os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-csh\n') - ) - - - if refinementProtocol=='pandda_refmac': - refinementProgram='refmac' - refinementParams=os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'multi-state-restraints.refmac.params') - mapCalculation = ( - 'fft hklin refine.mtz mapout 2fofc.map << EOF\n' - 'labin F1=FWT PHI=PHWT\n' - 'EOF\n' - '\n' - 'fft hklin refine.mtz mapout fofc.map << EOF\n' - 'labin F1=DELFWT PHI=PHDELWT\n' - 'EOF\n' ) - elif refinementProtocol=='pandda_phenix': - - if os.getcwd().startswith('/dls'): - module_load = 'module load phenix/1.13\n' - - refinementProgram='phenix' - refinementParams=os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'multi-state-restraints.phenix.params') - mapCalculation = ( - 'fft hklin refine.mtz mapout 2fofc.map << EOF\n' - 'labin F1=2FOFCWT PHI=PH2FOFCWT\n' - 'EOF\n' - '\n' - 'fft hklin refine.mtz mapout fofc.map << EOF\n' - 'labin F1=FOFCWT PHI=PHFOFCWT\n' - 'EOF\n' ) - - if make_all_links: - add_links_line = ( - 'ln -s Refine_%s/refine_%s.split.bound-state.pdb ./refine.split.bound-state.pdb\n' %(panddaSerial,Serial)+ - 'ln -s Refine_%s/refine_%s.split.ground-state.pdb ./refine.split.ground-state.pdb\n' %(panddaSerial,Serial)+ - 'ln -s Refine_%s/refine_%s.output.bound-state.pdb ./refine.output.bound-state.pdb\n' %(panddaSerial,Serial)+ - 'ln -s Refine_%s/refine_%s.output.ground-state.pdb ./refine.output.ground-state.pdb\n' %(panddaSerial,Serial) - ) - - - refmacCmds = ( - '#!'+os.getenv('SHELL')+'\n' - +pbs_line+ - '\n' - + module_load + - '\n' - +source+ - 'cd '+self.ProjectPath+'/'+self.xtalID+'\n' - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py %s %s %s %s\n' %(self.datasource,self.xtalID,'RefinementStatus','running') + - '\n' - 'giant.quick_refine' - ' input.pdb=%s' %RefmacParams['XYZIN']+ - ' mtz=%s' %RefmacParams['HKLIN']+ - ' cif=%s' %RefmacParams['LIBIN']+ - ' program=%s' %refinementProgram + - ' params=%s' %refinementParams+ - " dir_prefix='Refine_'" - " out_prefix='refine_%s'" %str(Serial)+ - " split_conformations='False'" - '\n' - 'cd '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(panddaSerial)+'\n' - - 'ln -s '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(panddaSerial)+'/refine_'+str(Serial)+'_001.pdb ' - +self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(panddaSerial)+'/refine_'+str(Serial)+'.pdb' +'\n' - - 'ln -s '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(panddaSerial)+'/refine_'+str(Serial)+'_001.mtz ' - +self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(panddaSerial)+'/refine_'+str(Serial)+'.mtz' +'\n' - - 'giant.split_conformations' - " input.pdb='refine_%s.pdb'" %str(Serial)+ - ' reset_occupancies=False' - ' suffix_prefix=split' - '\n' - 'giant.split_conformations' - " input.pdb='refine_%s.pdb'" %str(Serial)+ - ' reset_occupancies=True' - ' suffix_prefix=output ' - '\n' - +spider_plot+ - '\n' - 'phenix.molprobity refine_%s.pdb refine_%s.mtz\n' %(Serial,Serial)+ - '/bin/mv molprobity.out refine_molprobity.log\n' - 'module load phenix\n' - 'mmtbx.validate_ligands refine_%s.pdb refine_%s.mtz LIG > validate_ligands.txt\n' %(Serial,Serial)+ - 'cd '+self.ProjectPath+'/'+self.xtalID+'\n' - '\n' - 'ln -s Refine_%s/validate_ligands.txt .\n' %panddaSerial+ - 'ln -s Refine_%s/refine_molprobity.log .\n' %panddaSerial+ - '\n' - + add_links_line + - '\n' - 'mmtbx.validation_summary refine.pdb > validation_summary.txt\n' - '\n' - + mapCalculation + - '\n' - '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_after_refinement.py')+ - ' %s %s %s %s\n' %(self.datasource,self.xtalID,self.ProjectPath,os.path.join(self.ProjectPath,self.xtalID,'Refine_'+str(panddaSerial)))+ - '\n' - '/bin/rm %s/%s/REFINEMENT_IN_PROGRESS\n' %(self.ProjectPath,self.xtalID)+ - '\n' - ) - - Logfile.insert('writing refinement shell script to'+os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'refmac.csh')) - cmd = open(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial),'refmac.csh'),'w') - cmd.write(refmacCmds) - cmd.close() - - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) -# os.system('ssh artemis "cd %s/%s/Refine_%s; qsub refmac.csh"' %(self.ProjectPath,self.xtalID,Serial)) - Logfile.insert('changing directory to %s' %(os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial)))) - - if external_software['qsub']: - Logfile.insert('starting refinement on cluster') - os.system('qsub -P labxchem refmac.csh') - elif external_software['qsub_remote'] != '': - Logfile.insert('starting refinement on remote cluster') - remote_command=external_software['qsub_remote'].replace('qsub','cd %s; qsub' %os.path.join(self.ProjectPath,self.xtalID,'cootOut','Refine_'+str(Serial))) - os.system('%s -P labxchem refmac.csh' %remote_command) - print '%s -P labxchem refmac.csh' %remote_command - else: - Logfile.insert('changing permission of refmac.csh: chmod +x refmac.csh') - os.system('chmod +x refmac.csh') - Logfile.insert('starting refinement on local machine') - os.system('./refmac.csh &') - -# if '/work/' in os.getcwd(): -# os.system('ssh artemis "cd %s/%s/Refine_%s; qsub refmac.csh"' %(self.ProjectPath,self.xtalID,Serial)) -# else: -# os.system('./refmac.csh &') - - - - - def RefinementParams(self,RefmacParams): - self.RefmacParams=RefmacParams - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_title("Refmac Parameters") - self.vbox = gtk.VBox() - - self.hbox1=gtk.HBox() - self.hbox1.add(gtk.Label('Refine')) - self.cb = gtk.combo_box_new_text() - self.cb.connect("changed", self.ChooseBfacRefinement) - for item in ['isotropic','anisotropic']: - self.cb.append_text(item) - if 'ISOT' in self.RefmacParams['BREF']: - self.cb.set_active(0) - if 'ANIS' in self.RefmacParams['BREF']: - self.cb.set_active(1) - self.hbox1.add(self.cb) - self.hbox1.add(gtk.Label('temperature factors')) - self.vbox.add(self.hbox1) - - self.hbox2=gtk.HBox() - self.hbox2.add(gtk.Label('Number of Cycles: ')) - self.Ncycles=gtk.Entry() - self.Ncycles.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.Ncycles.connect("key-release-event", self.on_key_release_Ncycles) - self.Ncycles.set_text(self.RefmacParams['NCYCLES']) - self.hbox2.add(self.Ncycles) - self.vbox.add(self.hbox2) - - self.hbox3=gtk.HBox() - self.hbox3.add(gtk.Label('MATRIX WEIGHT: ')) - self.MATRIX_WEIGHT=gtk.Entry() - self.MATRIX_WEIGHT.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.MATRIX_WEIGHT.connect("key-release-event", self.on_key_release_MATRIX_WEIGHT) - self.MATRIX_WEIGHT.set_text(self.RefmacParams['MATRIX_WEIGHT']) - self.hbox3.add(self.MATRIX_WEIGHT) - self.vbox.add(self.hbox3) - - self.TLS = gtk.CheckButton('TLS (find TLS groups with phenix.find_tls_groups)') - self.TLS.connect("toggled", self.TLSCallback) - if self.RefmacParams['TLS']=='refi tlsc 10\n': self.TLS.set_active(True) - self.vbox.pack_start(self.TLS,False) - - self.NCS = gtk.CheckButton('NCS (if applicable') - self.NCS.connect("toggled", self.NCSCallback) - if self.RefmacParams['NCS']=='NCSR LOCAL\n': self.NCS.set_active(True) - self.vbox.pack_start(self.NCS,False) - - self.TWIN = gtk.CheckButton('Twin?') - self.TWIN.connect("toggled", self.TWINCallback) - if self.RefmacParams['TWIN']=='TWIN\n': self.TWIN.set_active(True) - self.vbox.pack_start(self.TWIN,False) - - self.OKbutton = gtk.Button(label="OK") - self.OKbutton.connect("clicked",self.OK) - self.vbox.add(self.OKbutton) - - self.window.add(self.vbox) - self.window.show_all() - return self.RefmacParams - - - def TLSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TLS']='refi tlsc 10\n' - self.RefmacParams['TLSIN']='refmac.tls\n' - self.RefmacParams['TLSOUT']='out.tls\n' - self.RefmacParams['TLSADD']='TLSO ADDU\n' - else: - self.RefmacParams['TLS']='' - self.RefmacParams['TLSIN']='' - self.RefmacParams['TLSOUT']='' - self.RefmacParams['TLSADD']='' - return self.RefmacParams - - def NCSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['NCS']='NCSR LOCAL\n' - else: - self.RefmacParams['NCS']='' - return self.RefmacParams - - def ChooseBfacRefinement(self,widget): - if widget.get_active_text()=='isotropic': - self.RefmacParams['BREF']=' bref ISOT\n' - if widget.get_active_text()=='anisotropic': - self.RefmacParams['BREF']=' bref ANIS\n' - return self.RefmacParams - - def on_key_release_Ncycles(self, widget, event): - print widget.get_text() - self.RefmacParams['NCYCLES'] = widget.get_text() - return self.RefmacParams - - def on_key_release_MATRIX_WEIGHT(self, widget, event): - self.RefmacParams['MATRIX_WEIGHT'] = widget.get_text() - return self.RefmacParams - - def TWINCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TWIN']='TWIN\n' - else: - self.RefmacParams['TWIN']='' - return self.RefmacParams - - def OK(self,widget): - self.window.destroy() - - - def ParamsFromPreviousCycle(self,Serial): - - RefmacParams={ 'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': '' } - - if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - if line.startswith('refi tlsc'): - RefmacParams['TLS']=line - if line.startswith('TLSO'): - RefmacParams['TLSADD']=line - if line.startswith('NCSR LOCAL'): - RefmacParams['NCS']=line - if line.startswith(' bref '): - RefmacParams['BREF']=line - if line.startswith('ncyc'): - RefmacParams['Ncycles'] = line.split()[1] - if line.startswith('weight'): - RefmacParams['MATRIX_WEIGHT'] = line.split()[len(line.split())-1] - if line.startswith('TWIN'): - RefmacParams['TWIN']=line - - return RefmacParams - - def GetRefinementHistory(self): -# RefinementHistory='' - RefinementCycle = [] - RcrystList=[] - RfreeList=[] - - found = False - for item in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if item.startswith(os.path.join(self.ProjectPath,self.xtalID,'Refine_')): - print item[item.rfind('_')+1:] - RefinementCycle.append(int(item[item.rfind('_')+1:])) - found = True - if found: - for cycle in sorted(RefinementCycle): -# for cycle in RefinementCycle: -# Rcryst=0 -# Rfree=0 -# LigandCC=0 - try: - found_Rcryst=False - found_Rfree=False - newestPDB = max(glob.iglob(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/refine_'+str(cycle)+'.pdb'), key=os.path.getctime) - for line in open(newestPDB): - if line.startswith('REMARK 3 R VALUE (WORKING + TEST SET) :'): - Rcryst = line.split()[9] - RcrystList.append(float(Rcryst)) - found_Rcryst=True - if line.startswith('REMARK 3 FREE R VALUE :'): - Rfree = line.split()[6] - RfreeList.append(float(Rfree)) - found_Rfree=True - if not found_Rcryst: - RcrystList.append(0) - if not found_Rfree: - RfreeList.append(0) -# if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# if line.startswith('| LIG'): LigandCC = line.split()[6] -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - except ValueError: - RcrystList.append(0) - RfreeList.append(0) -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - else: - RefinementCycle = [0] - RcrystList=[0] - RfreeList=[0] - print RefinementCycle,RcrystList,RfreeList - return(sorted(RefinementCycle),RcrystList,RfreeList) - - -class RefineOld(object): - - def __init__(self,ProjectPath,xtalID,compoundID,datasource): - self.ProjectPath = ProjectPath - self.xtalID = xtalID - self.compoundID = compoundID - self.prefix = 'refine' - self.datasource=datasource - - def GetSerial(self): - # check if there were already previous refinements - # if no: create a folder Refine_1 - # if yes: create a folder Refine_ - temp = [] - found = 0 - if os.path.isdir(os.path.join(self.ProjectPath,self.xtalID)): - for item in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if item.startswith(os.path.join(self.ProjectPath,self.xtalID,'Refine_')): - print int(item[item.rfind('_')+1:]) - temp.append(int(item[item.rfind('_')+1:])) - found = 1 - if found: - Serial = max(temp) + 1 - else: - Serial=1 - return Serial - - - def RunRefmac(self,Serial,RefmacParams,external_software,xce_logfile): - Logfile=XChemLog.updateLog(xce_logfile) - Serial=str(Serial) - - # first check if refinement is ongoing and exit if yes - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'REFINEMENT_IN_PROGRESS')): -# coot.info_dialog('*** REFINEMENT IN PROGRESS ***') - Logfile.insert('cannot start new refinement for %s: *** REFINEMENT IN PROGRESS ***' %self.xtalID) - return None - - ####################################################### - # HKLIN & HKLOUT - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'.free.mtz')): - RefmacParams['HKLIN']='HKLIN '+os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'.free.mtz \\\n') - elif os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz')): - RefmacParams['HKLIN']='HKLIN '+os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz \\\n') - else: - Logfile.insert('%s: cannot find HKLIN for refinement; aborting...' %self.xtalID) - return None - RefmacParams['HKLOUT']='HKLOUT '+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refine_'+Serial+'.mtz \\\n') - - ####################################################### - # XYZIN & XYZOUT - RefmacParams['XYZIN']='XYZIN '+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'in.pdb \\\n') - RefmacParams['XYZOUT']='XYZOUT '+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refine_'+Serial+'.pdb \\\n') - - ####################################################### - # LIBIN & LIBOUT - found_cif=False - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.compoundID+'.cif')): - found_cif=True - # in cases where multiple liagnds are present (e.g. NOG, ATP) the user for now needs to put - # the respective dictionary into the xtalID folder - # need to think of a better mechanism in the future - additional_cif=False - additional_cif_file='' - for file in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if file.endswith('.cif'): - if self.compoundID not in file: - additional_cif_file=file -# additional_cif=True <- should be true, but need to check this part of the code! 16/11/2016 - additional_cif=False - if additional_cif: - Cmds = ( - '#!'+os.getenv('SHELL')+'\n' - '\n' - '$CCP4/bin/libcheck << eof \n' - '_Y\n' - '_FILE_L '+os.path.join(self.ProjectPath,self.xtalID,self.compoundID+'.cif')+'\n' - '_FILE_L2 '+additional_cif_file+'\n' - '_FILE_O '+os.path.join(self.ProjectPath,self.xtalID,'combined_cif')+'\n' - '_END\n' - 'eof\n' - ) - os.chdir(os.path.join(self.ProjectPath,self.xtalID)) - print Cmds - os.system(Cmds) - RefmacParams['LIBIN']='LIBIN '+self.ProjectPath+'/'+self.xtalID+'/combined_cif.lib \\\n' - else: - RefmacParams['LIBIN']='LIBIN '+self.ProjectPath+'/'+self.xtalID+'/'+self.compoundID+'.cif \\\n' - RefmacParams['LIBOUT']='LIBOUT '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'/refine_'+Serial+'.cif \\\n' - if not found_cif: - # this should actually not be necessary, but the following scenario can happen: - # if a new data source is created from a file system, but smiles and compoundID where not updated; - # so the ligand may still be in the structure, but since the compoundID is unknown to the datasource, - # its restraints won't be read in and refmac will fail - for file in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if file.endswith('.cif'): - RefmacParams['LIBIN']='LIBIN '+file+' \\\n' - RefmacParams['LIBOUT']='LIBOUT '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'/refine_'+Serial+'.cif \\\n' - break - - ####################################################### - # TLSIN & TLSOUT - findTLS='\n' - TLSphenix='' - if RefmacParams['TLS'].startswith('refi'): - if external_software['phenix.find_tls_groups']: - findTLS=os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','phenix_find_TLS_groups.py')+' in.pdb\n' - RefmacParams['TLSIN']='TLSIN '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'/refmac.tls \\\n' - RefmacParams['TLSOUT']='TLSOUT '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'/refine.tls \\\n' - TLSphenix=' phenix.tls ' - else: - RefmacParams['TLS']='\n' - - -# ####################################################### -# # create folder for new refinement cycle -# os.mkdir(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial)) -# -# ####################################################### -# # write PDB file -# # now take protein pdb file and write it to newly create Refine_ folder -# # note: the user has to make sure that the ligand file was merged into main file -# for item in coot_utils_XChem.molecule_number_list(): -# if coot.molecule_name(item).endswith(self.prefix+'.pdb'): -# coot.write_pdb_file(item,os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'in.pdb')) - - ####################################################### - # PANDDAs stuff - # only use occupancy refinement if EVENT map is present - occupancy_refinement='' - if external_software['giant.create_occupancy_params']: - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial)) - cmd = ( '#!'+os.getenv('SHELL')+'\n' - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','xce.setup-sh')+'\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh')+'\n' - "giant.create_occupancy_params pdb=in.pdb refmac_occ_out='refmac_refine.params'\n" ) -# os.system("giant.create_occupancy_params pdb=in.pdb refmac_occ_out='refmac_refine.params'") -# os.system(cmd) - print "==> XCE: running giant.create_occupancy_params pdb=in.pdb refmac_occ_out='refmac_refine.params'" - os.system("giant.create_occupancy_params pdb=in.pdb refmac_occ_out='refmac_refine.params'") - # quick fix for the moment; need to talk to Nick since this should not be necessary - try: - params_file = fileinput.input('refmac_refine.params',inplace=True) - for line in params_file: - if 'incomplete' in line: - line=line.replace('incomplete','complete') - print line, -# elif 'occupancy refine' in line: -# line=line.replace('occupancy refine','occupancy refine ncycle 10\noccupancy refine') -# print line, - else: - print line, - params_file.close() - except OSError: - # this may happen in case giant.create_occupancy_params did not produce a params output file - pass - - print '==> XCE: waiting 5 seconds for giant.create_occupancy_params to finish...' - time.sleep(5) - print '==> XCE: done!' - - print '==> XCE: assembling refmac.csh' - - create_bound_conformation='' - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refmac_refine.params')): - occupancy_refinement='@refmac_refine.params\n' - create_bound_conformation="/bin/rm *bound.pdb\ngiant.strip_conformations pdb=refine.pdb suffix='.bound.pdb'\n" - - ####################################################### - # we write 'REFINEMENT_IN_PROGRESS' immediately to avoid unncessary refiment - os.chdir(os.path.join(self.ProjectPath,self.xtalID)) - os.system('touch REFINEMENT_IN_PROGRESS') - - ####################################################### - # clean up! - # and remove all files which will be re-created by current refinement cycle - os.system('/bin/rm refine.pdb refine.mtz validation_summary.txt validate_ligands.txt 2fofc.map fofc.map refine_molprobity.log') - - if external_software['qsub']: - pbs_line='#PBS -joe -N XCE_refmac\n' - else: - pbs_line='\n' - - ####################################################### - # weight - if str(RefmacParams['MATRIX_WEIGHT']).lower() == 'auto': - weight='weight AUTO\n' - else: - weight='weight matrix '+str(RefmacParams['MATRIX_WEIGHT'])+'\n' - - ####################################################### - # PANDDA validation @ spider plot - spider_plot='' - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-ensemble-model.pdb')): - if os.path.isfile(os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz')): - pdb_two=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-ensemble-model.pdb') - mtz_two=os.path.join(self.ProjectPath,self.xtalID,self.xtalID+'-pandda-input.mtz') - pdb_one=os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refine_'+Serial+'.pdb') - mtz_one=os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refine_'+Serial+'.mtz') - spider_plot='$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/resort_ligand_atoms.py %s %s\n\n' %(pdb_two,pdb_one) - spider_plot+='giant.score_model pdb1=%s mtz1=%s pdb2=%s mtz2=%s res_names=LIG,UNL,DRG,FRG\n' %(pdb_one,mtz_one,pdb_two,mtz_two) -# spider_plot='giant.score_model pdb1=%s mtz1=%s pdb2=%s mtz2=%s res_names=LIG,UNL,DRG,FRG\n' %(pdb_one,mtz_one,pdb_two,mtz_two) - - ####################################################### - # PHENIX stuff (if working at DLS) - module_load='' - if os.getcwd().startswith('/dls'): - module_load='module load phenix\n' - - source ='' - if 'bash' in os.getenv('SHELL'): - source = ( - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','xce.setup-sh')+'\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh')+'\n' ) - elif 'csh' in os.getenv('SHELL'): - source = ( - 'setenv XChemExplorer_DIR '+os.getenv('XChemExplorer_DIR')+'\n' - '\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','xce.setup-csh')+'\n' - 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-csh')+'\n' ) - - - refmacCmds = ( - '#!'+os.getenv('SHELL')+'\n' - +pbs_line+ - '\n' - + module_load + - '\n' - + source + - 'cd '+self.ProjectPath+'/'+self.xtalID+'/Refine_'+Serial+'\n' - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py %s %s %s %s\n' %(self.datasource,self.xtalID,'RefinementStatus','running') + - '\n' - +findTLS+ - 'refmac5 ' - +RefmacParams['HKLIN'] - +RefmacParams['HKLOUT'] - +RefmacParams['XYZIN'] - +RefmacParams['XYZOUT'] - +RefmacParams['LIBIN'] - +RefmacParams['LIBOUT'] - +RefmacParams['TLSIN'] - +RefmacParams['TLSOUT']+ - ' << EOF > refmac.log\n' - 'make -\n' - ' hydrogen ALL -\n' - ' hout NO -\n' - ' peptide NO -\n' - ' cispeptide YES -\n' - ' ssbridge YES -\n' - ' symmetry YES -\n' - ' sugar YES -\n' - ' connectivity NO -\n' - ' link NO\n' - +RefmacParams['NCS']+ - 'refi -\n' - ' type REST -\n' - ' resi MLKF -\n' - ' meth CGMAT -\n' - +RefmacParams['BREF'] - +RefmacParams['TLS'] - +RefmacParams['TWIN']+ - 'ncyc '+RefmacParams['NCYCLES']+'\n' - 'scal -\n' - ' type SIMP -\n' - ' LSSC -\n' - ' ANISO -\n' - ' EXPE\n' - +weight+ - 'solvent YES\n' - +occupancy_refinement+ - 'monitor MEDIUM -\n' - ' torsion 10.0 -\n' - ' distance 10.0 -\n' - ' angle 10.0 -\n' - ' plane 10.0 -\n' - ' chiral 10.0 -\n' - ' bfactor 10.0 -\n' - ' bsphere 10.0 -\n' - ' rbond 10.0 -\n' - ' ncsr 10.0\n' - 'labin FP=F SIGFP=SIGF FREE=FreeR_flag\n' - 'labout FC=FC FWT=FWT PHIC=PHIC PHWT=PHWT DELFWT=DELFWT PHDELWT=PHDELWT FOM=FOM\n' - +RefmacParams['TLSADD']+'\n' - 'DNAME '+self.xtalID+'\n' - 'END\n' - 'EOF\n' - '\n' - +spider_plot+ - '\n' - 'phenix.molprobity refine_%s.pdb refine_%s.mtz\n' %(Serial,Serial)+ - '/bin/mv molprobity.out refine_molprobity.log\n' - 'mmtbx.validate_ligands refine_%s.pdb refine_%s.mtz LIG > validate_ligands.txt\n' %(Serial,Serial)+ - 'cd '+self.ProjectPath+'/'+self.xtalID+'\n' - '#ln -s %s/%s/Refine_%s/refine_%s.pdb refine.pdb\n' %(self.ProjectPath,self.xtalID,Serial,Serial)+ - '#ln -s %s/%s/Refine_%s/refine_%s.mtz refine.mtz\n' %(self.ProjectPath,self.xtalID,Serial,Serial)+ - 'ln -s ./Refine_%s/refine_%s.pdb refine.pdb\n' %(Serial,Serial)+ - 'ln -s ./Refine_%s/refine_%s.mtz refine.mtz\n' %(Serial,Serial)+ - '\n' - +create_bound_conformation+ - '\n' - 'ln -s Refine_%s/validate_ligands.txt .\n' %Serial+ - 'ln -s Refine_%s/refine_molprobity.log .\n' %Serial+ - 'mmtbx.validation_summary refine.pdb > validation_summary.txt\n' - '\n' - 'fft hklin refine.mtz mapout 2fofc.map << EOF\n' - 'labin F1=FWT PHI=PHWT\n' - 'EOF\n' - '\n' - 'fft hklin refine.mtz mapout fofc.map << EOF\n' - 'labin F1=DELFWT PHI=PHDELWT\n' - 'EOF\n' - '\n' - '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_after_refinement.py')+ - ' %s %s %s %s\n' %(self.datasource,self.xtalID,self.ProjectPath,os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial))+ - '\n' - '/bin/rm %s/%s/REFINEMENT_IN_PROGRESS\n' %(self.ProjectPath,self.xtalID)+ - '\n' - ) - - Logfile.insert('writing refinement shell script to'+os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refmac.csh')) - cmd = open(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial,'refmac.csh'),'w') - cmd.write(refmacCmds) - cmd.close() - - os.chdir(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial)) -# os.system('ssh artemis "cd %s/%s/Refine_%s; qsub refmac.csh"' %(self.ProjectPath,self.xtalID,Serial)) - Logfile.insert('changing directory to %s' %(os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial))) - if external_software['qsub']: - Logfile.insert('starting refinement on cluster') - os.system('qsub -P labxchem refmac.csh') - elif external_software['qsub_remote'] != '': - Logfile.insert('starting refinement on remote cluster') - remote_command=external_software['qsub_remote'].replace('qsub','cd %s; qsub' %os.path.join(self.ProjectPath,self.xtalID,'Refine_'+Serial)) - os.system('%s -P labxchem refmac.csh' %remote_command) - print '%s -P labxchem refmac.csh' %remote_command - else: - Logfile.insert('changing permission of refmac.csh: chmod +x refmac.csh') - os.system('chmod +x refmac.csh') - Logfile.insert('starting refinement on local machine') - os.system('./refmac.csh &') -# if '/work/' in os.getcwd(): -# os.system('ssh artemis "cd %s/%s/Refine_%s; qsub refmac.csh"' %(self.ProjectPath,self.xtalID,Serial)) -# else: -# os.system('./refmac.csh &') - - - - - def RefinementParams(self,RefmacParams): - self.RefmacParams=RefmacParams - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.connect("delete_event", gtk.main_quit) - self.window.set_border_width(10) - self.window.set_title("Refmac Parameters") - self.vbox = gtk.VBox() - - self.hbox1=gtk.HBox() - self.hbox1.add(gtk.Label('Refine')) - self.cb = gtk.combo_box_new_text() - self.cb.connect("changed", self.ChooseBfacRefinement) - for item in ['isotropic','anisotropic']: - self.cb.append_text(item) - if 'ISOT' in self.RefmacParams['BREF']: - self.cb.set_active(0) - if 'ANIS' in self.RefmacParams['BREF']: - self.cb.set_active(1) - self.hbox1.add(self.cb) - self.hbox1.add(gtk.Label('temperature factors')) - self.vbox.add(self.hbox1) - - self.hbox2=gtk.HBox() - self.hbox2.add(gtk.Label('Number of Cycles: ')) - self.Ncycles=gtk.Entry() - self.Ncycles.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.Ncycles.connect("key-release-event", self.on_key_release_Ncycles) - self.Ncycles.set_text(self.RefmacParams['NCYCLES']) - self.hbox2.add(self.Ncycles) - self.vbox.add(self.hbox2) - - self.hbox3=gtk.HBox() - self.hbox3.add(gtk.Label('MATRIX WEIGHT: ')) - self.MATRIX_WEIGHT=gtk.Entry() - self.MATRIX_WEIGHT.add_events(gtk.gdk.KEY_RELEASE_MASK) - self.MATRIX_WEIGHT.connect("key-release-event", self.on_key_release_MATRIX_WEIGHT) - self.MATRIX_WEIGHT.set_text(self.RefmacParams['MATRIX_WEIGHT']) - self.hbox3.add(self.MATRIX_WEIGHT) - self.vbox.add(self.hbox3) - - self.TLS = gtk.CheckButton('TLS (find TLS groups with phenix.find_tls_groups)') - self.TLS.connect("toggled", self.TLSCallback) - if self.RefmacParams['TLS']=='refi tlsc 10\n': self.TLS.set_active(True) - self.vbox.pack_start(self.TLS,False) - - self.NCS = gtk.CheckButton('NCS (if applicable') - self.NCS.connect("toggled", self.NCSCallback) - if self.RefmacParams['NCS']=='NCSR LOCAL\n': self.NCS.set_active(True) - self.vbox.pack_start(self.NCS,False) - - self.TWIN = gtk.CheckButton('Twin?') - self.TWIN.connect("toggled", self.TWINCallback) - if self.RefmacParams['TWIN']=='TWIN\n': self.TWIN.set_active(True) - self.vbox.pack_start(self.TWIN,False) - - self.OKbutton = gtk.Button(label="OK") - self.OKbutton.connect("clicked",self.OK) - self.vbox.add(self.OKbutton) - - self.window.add(self.vbox) - self.window.show_all() - return self.RefmacParams - - - def TLSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TLS']='refi tlsc 10\n' - self.RefmacParams['TLSIN']='refmac.tls\n' - self.RefmacParams['TLSOUT']='out.tls\n' - self.RefmacParams['TLSADD']='TLSO ADDU\n' - else: - self.RefmacParams['TLS']='' - self.RefmacParams['TLSIN']='' - self.RefmacParams['TLSOUT']='' - self.RefmacParams['TLSADD']='' - return self.RefmacParams - - def NCSCallback(self, widget): - if widget.get_active(): - self.RefmacParams['NCS']='NCSR LOCAL\n' - else: - self.RefmacParams['NCS']='' - return self.RefmacParams - - def ChooseBfacRefinement(self,widget): - if widget.get_active_text()=='isotropic': - self.RefmacParams['BREF']=' bref ISOT\n' - if widget.get_active_text()=='anisotropic': - self.RefmacParams['BREF']=' bref ANIS\n' - return self.RefmacParams - - def on_key_release_Ncycles(self, widget, event): - print widget.get_text() - self.RefmacParams['NCYCLES'] = widget.get_text() - return self.RefmacParams - - def on_key_release_MATRIX_WEIGHT(self, widget, event): - self.RefmacParams['MATRIX_WEIGHT'] = widget.get_text() - return self.RefmacParams - - def TWINCallback(self, widget): - if widget.get_active(): - self.RefmacParams['TWIN']='TWIN\n' - else: - self.RefmacParams['TWIN']='' - return self.RefmacParams - - def OK(self,widget): - self.window.destroy() - - - def ParamsFromPreviousCycle(self,Serial): - - RefmacParams={ 'HKLIN': '', 'HKLOUT': '', - 'XYZIN': '', 'XYZOUT': '', - 'LIBIN': '', 'LIBOUT': '', - 'TLSIN': '', 'TLSOUT': '', - 'TLSADD': '', - 'NCYCLES': '10', - 'MATRIX_WEIGHT': 'AUTO', - 'BREF': ' bref ISOT\n', - 'TLS': '', - 'NCS': '', - 'TWIN': '' } - - if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(Serial)+'/refmac.csh'): - if line.startswith('refi tlsc'): - RefmacParams['TLS']=line - if line.startswith('TLSO'): - RefmacParams['TLSADD']=line - if line.startswith('NCSR LOCAL'): - RefmacParams['NCS']=line - if line.startswith(' bref '): - RefmacParams['BREF']=line - if line.startswith('ncyc'): - RefmacParams['Ncycles'] = line.split()[1] - if line.startswith('weight'): - RefmacParams['MATRIX_WEIGHT'] = line.split()[len(line.split())-1] - if line.startswith('TWIN'): - RefmacParams['TWIN']=line - - return RefmacParams - - def GetRefinementHistory(self): -# RefinementHistory='' - RefinementCycle = [] - RcrystList=[] - RfreeList=[] - - found = False - for item in glob.glob(os.path.join(self.ProjectPath,self.xtalID,'*')): - if item.startswith(os.path.join(self.ProjectPath,self.xtalID,'Refine_')): - print item[item.rfind('_')+1:] - RefinementCycle.append(int(item[item.rfind('_')+1:])) - found = True - if found: - for cycle in sorted(RefinementCycle): -# for cycle in RefinementCycle: -# Rcryst=0 -# Rfree=0 -# LigandCC=0 - try: - found_Rcryst=False - found_Rfree=False - newestPDB = max(glob.iglob(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/refine_'+str(cycle)+'.pdb'), key=os.path.getctime) - for line in open(newestPDB): - if line.startswith('REMARK 3 R VALUE (WORKING + TEST SET) :'): - Rcryst = line.split()[9] - RcrystList.append(float(Rcryst)) - found_Rcryst=True - if line.startswith('REMARK 3 FREE R VALUE :'): - Rfree = line.split()[6] - RfreeList.append(float(Rfree)) - found_Rfree=True - if not found_Rcryst: - RcrystList.append(0) - if not found_Rfree: - RfreeList.append(0) -# if os.path.isfile(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# for line in open(self.ProjectPath+'/'+self.xtalID+'/Refine_'+str(cycle)+'/validate_ligands.txt'): -# if line.startswith('| LIG'): LigandCC = line.split()[6] -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - except ValueError: - RcrystList.append(0) - RfreeList.append(0) -# RefinementHistory=RefinementHistory+str(cycle).rjust(10)+str(R).rjust(10)+str(Rfree).rjust(10)+str(LigandCC).rjust(10)+'\n' - else: - RefinementCycle = [0] - RcrystList=[0] - RfreeList=[0] - print RefinementCycle,RcrystList,RfreeList - return(sorted(RefinementCycle),RcrystList,RfreeList) - - diff --git a/lib/XChemThread.py b/lib/XChemThread.py deleted file mode 100755 index 72df4e3c..00000000 --- a/lib/XChemThread.py +++ /dev/null @@ -1,2773 +0,0 @@ -# last edited: 31/07/2017, 10:30 - -import os, sys, glob -from datetime import datetime -from PyQt4 import QtGui, QtCore - -import time -import pickle -import cPickle -import base64 -import math -import subprocess -from datetime import datetime -import time -import getpass -import csv -import tarfile - -from iotbx import mtz -from iotbx.reflection_file_reader import any_reflection_file - -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -from XChemUtils import process -from XChemUtils import parse -from XChemUtils import queue -from XChemUtils import mtztools -from XChemUtils import pdbtools -from XChemUtils import helpers -from XChemUtils import reference -from XChemUtils import misc -import XChemDB -import XChemLog -import XChemMain - -import iotbx.mtz - - -class synchronise_db_and_filesystem(QtCore.QThread): - - ''' - - remove broken links - - insert new samples in DB - - update data for existing samples - ''' - - def __init__(self,initial_model_directory,datasource,panddas_directory,xce_logfile,mode): - QtCore.QThread.__init__(self) - self.initial_model_directory=initial_model_directory - self.datasource=datasource - self.db=XChemDB.data_source(self.datasource) - self.all_samples_in_datasource=self.db.get_all_samples_in_data_source_as_list() - self.panddas_directory=panddas_directory - self.Logfile=XChemLog.updateLog(xce_logfile) - self.mode=mode - - def run(self): - self.Logfile.insert('synchronising database and filesystem') - self.Logfile.insert('current project directory: '+self.initial_model_directory) - - # - # get list of xtals - # - - self.xtal_list = [] - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - if self.mode != 'project_directory': - # if only a single xtal is synched, then self.mode==xtalID - self.Logfile.insert('synchronising '+self.mode+' only') - self.xtal_list.append(self.mode) - else: - if len(glob.glob(os.path.join(self.initial_model_directory,'*'))) != 0: - progress_step=100/float(len(glob.glob(os.path.join(self.initial_model_directory,'*')))) - self.Logfile.insert('found '+str(len(glob.glob(os.path.join(self.initial_model_directory,'*'))))+' samples in project directory') - for directory in sorted(glob.glob(os.path.join(self.initial_model_directory,'*'))): - try: - os.chdir(directory) - except OSError: - # this could happen if the user accidentaly left a file in the project directory - continue - if os.listdir(directory) == []: - self.Logfile.warning(directory + ' is empty; skipping...') - continue - xtal=directory[directory.rfind('/')+1:] - self.xtal_list.append(xtal) - - # - # go through list - # - - for xtal in self.xtal_list: - self.Logfile.insert('directory name: '+xtal+' = sampleID in database') - os.chdir(os.path.join(self.initial_model_directory,xtal)) - if xtal not in self.all_samples_in_datasource: - self.Logfile.insert('sampleID not found in database: inserting '+xtal) - self.db.execute_statement("insert into mainTable (CrystalName) values ('{0!s}');".format(xtal)) - self.all_samples_in_datasource.append(xtal) - - db_dict=self.db.get_db_dict_for_sample(xtal) - - db_dict['ProjectDirectory'] = self.initial_model_directory - - db_dict=self.sync_data_processing(xtal,db_dict) - - db_dict=self.sync_dimple_results(xtal,db_dict) - - db_dict=self.sync_compound_information(db_dict) - - db_dict=self.sync_refinement_results(xtal,db_dict) - - if db_dict != {}: - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'updating datasource for '+xtal) - self.db.update_data_source(xtal,db_dict) - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.Logfile.insert('database mainTable update finished') - self.Logfile.insert('updating panddaTable') - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'updating panddaTable') -# self.sync_pandda_table() - self.sync_pandda_table_NEW() - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'database panddaTable update finished') - self.Logfile.insert('database panddaTable update finished') - - self.emit(QtCore.SIGNAL('datasource_menu_reload_samples')) - - - def change_absolute_to_relative_links(self,target,filename): - os.unlink(filename) - os.symlink(os.path.relpath(target),filename) - self.Logfile.insert('{0!s} -> {1!s}'.format(os.readlink(filename), target)) - - def find_file(self,filename,xtal): - found_file=False - for files in glob.glob('*'): - if files == filename: - # at this point, this could ba a file or a (broken) symbolic link - try: - link=os.readlink(filename) - if link.startswith('/'): - if os.path.isfile(link.replace(link[:link.find(xtal)],self.initial_model_directory+'/')): - target=link.replace(link[:link.find(xtal)],self.initial_model_directory+'/') - found_file=True - self.change_absolute_to_relative_links(target,filename) - elif os.path.isfile(files): - # this will leave the absolute path - found_file=True - else: - self.Logfile.insert('removing broken link: '+filename) - os.system('/bin/rm {0!s} 2> /dev/null'.format(filename)) - else: - if not os.path.isfile(link): - self.Logfile.insert('removing broken link: '+filename) - os.system('/bin/rm {0!s} 2> /dev/null'.format(filename)) - else: - found_file=True - except OSError: - if os.path.isfile(filename): - found_file=True - break - return found_file - - - - - def sync_data_processing(self,xtal,db_dict): - - # AIMLESS logfile - - # in case the MTZ file which is used for refinement is different to the one used for refinement - if os.path.isfile('refine.mtz'): - if os.path.isfile(xtal+'.free.mtz'): - freeMTZ=mtztools(xtal+'.free.mtz') - nREFfree=freeMTZ.get_number_measured_reflections() - if os.path.isfile(xtal+'.mtz'): - procMTZ=mtztools(xtal+'.mtz') - nREF=procMTZ.get_number_measured_reflections() - CC,errorMessage=freeMTZ.calculate_correlaton_between_intensities_in_mtzfiles(xtal+'.mtz') - self.Logfile.insert('%s: calculating CC between %s.free.mtz (%s refl) and %s.mtz (%s refl): %s' %(xtal,xtal,str(nREFfree),xtal,str(nREF),str(CC))) - if errorMessage != '': - self.Logfile.insert('pointless failed with the following error: %s' %errorMessage) - - try: - if float(CC) < 0.999: - self.Logfile.insert('correlation coefficient between the two files is below 0.999; will try to understand from dimple.log which one was used for initial map calculation') - if os.path.isfile('dimple/dimple_rerun_on_selected_file/dimple/dimple.log'): - foundLine=False - mtzin='' - for line in open('dimple/dimple_rerun_on_selected_file/dimple/dimple.log'): - if foundLine: - mtzin=line.replace(' ','').replace('\n','').replace('\r','') - self.Logfile.insert('%s was used for inital map calculation' %mtzin) - break - if line.startswith(' --no-cleanup'): - foundLine=True - - if os.path.isfile(mtzin): - self.Logfile.insert('%s: mtzfile used for refinement is not the same as the one chosen from autoprocessing' %xtal) - self.Logfile.insert('%s: current mtzfile after autoprocessing: %s' %(xtal,os.path.realpath(xtal+'.mtz'))) - self.Logfile.insert('%s: removing links for %s.mtz/%s.log' %(xtal,xtal,xtal)) - os.system('/bin/rm %s.mtz 2> /dev/null' %xtal) - os.system('/bin/rm %s.log 2> /dev/null' %xtal) - self.Logfile.insert('linking %s to %s.mtz' %(os.path.relpath(mtzin),xtal)) - os.symlink(os.path.relpath(mtzin),xtal+'.mtz') - for logfile in glob.glob(os.path.join(mtzin[:mtzin.rfind('/')],'*log')): - self.Logfile.insert('linking %s to %s.log' %(os.path.relpath(logfile),xtal)) - os.symlink(os.path.relpath(logfile),xtal+'.log') - break - - except ValueError: - self.Logfile.insert('something went wrong: calculated CC value does not seem to be a floating point number') - - found_logfile=False - if os.path.isfile(xtal+'.log'): - found_logfile=True -# db_dict['DataProcessingPathToLogfile']=os.path.realpath(xtal+'.log').replace(os.getcwd()+'/','') - db_dict['DataProcessingPathToLogfile']=os.path.realpath(xtal+'.log') - db_dict['DataProcessingLOGfileName']=xtal+'.log' - if db_dict['DataCollectionOutcome']=='None' or db_dict['DataCollectionOutcome']=='': - db_dict['DataCollectionOutcome']='success' - aimless_results=parse().read_aimless_logfile(xtal+'.log') - db_dict.update(aimless_results) - else: - db_dict['DataProcessingPathToLogfile']='' - db_dict['DataProcessingLOGfileName']='' - - # MTZ file - -# found_mtzfile=self.find_file(xtal+'.mtz',xtal) -# if found_mtzfile: - if os.path.isfile(xtal+'.mtz'): - db_dict['DataProcessingPathToMTZfile']=os.path.realpath(xtal+'.mtz') -# db_dict['DataProcessingPathToMTZfile']=os.path.realpath(xtal+'.mtz').replace(os.getcwd()+'/','') - db_dict['DataProcessingMTZfileName']=xtal+'.mtz' - if not found_logfile: - mtz_info=mtztools(xtal+'.mtz').get_information_for_datasource() - db_dict.update(mtz_info) - db_dict['DataCollectionOutcome']='success' - else: - db_dict['DataProcessingPathToMTZfile']='' - db_dict['DataProcessingMTZfileName']='' - - return db_dict - - - def sync_dimple_results(self,xtal,db_dict): - - # DIMPLE pdb - -# found_dimple_pdb=self.find_file('dimple.pdb',xtal) -# if found_dimple_pdb: - if os.path.isfile('dimple.pdb'): -# db_dict['DimplePathToPDB']=os.path.realpath('dimple.pdb').replace(os.getcwd()+'/','') - db_dict['DimplePathToPDB']=os.path.realpath('dimple.pdb') - pdb_info=parse().PDBheader('dimple.pdb') - db_dict['DimpleRcryst']=pdb_info['Rcryst'] - db_dict['DimpleRfree']=pdb_info['Rfree'] - db_dict['DimpleResolutionHigh']=pdb_info['ResolutionHigh'] - db_dict['DimpleStatus']='finished' - else: - db_dict['DimplePathToPDB']='' - db_dict['DimpleRcryst']='' - db_dict['DimpleRfree']='' - db_dict['DimpleResolutionHigh']='' - db_dict['DimpleStatus']='pending' - # DIMPLE mtz - - dimple_path='' -# found_dimple_mtz=self.find_file('dimple.mtz',xtal) -# if found_dimple_mtz: - if os.path.isfile('dimple.mtz'): -# db_dict['DimplePathToMTZ']=os.path.realpath('dimple.mtz').replace(os.getcwd()+'/','') - db_dict['DimplePathToMTZ']=os.path.realpath('dimple.mtz') - dimple_mtz=db_dict['DimplePathToMTZ'] - dimple_path=dimple_mtz[:dimple_mtz.rfind('/')] - else: - db_dict['DimplePathToMTZ']='' - db_dict['DimpleStatus']='pending' - - if os.path.isfile(os.path.join(dimple_path,'dimple','dimple_rerun_on_selected_file','dimple_run_in_progress')): - db_dict['DimpleStatus']='running' - - # MTZ free file - -# found_free_mtz=self.find_file(xtal+'.free.mtz',xtal) -# if found_free_mtz: - if os.path.isfile(xtal+'.free.mtz'): - db_dict['RefinementMTZfree']=os.path.realpath(xtal+'.free.mtz') -# db_dict['RefinementMTZfree']=os.path.realpath(xtal+'.free.mtz').replace(os.getcwd()+'/','') - else: - db_dict['RefinementMTZfree']='' - os.system('/bin/rm %s.free.mtz 2> /dev/null' %xtal) - if os.path.isfile(os.path.join(dimple_path,'prepared2.mtz')): - os.symlink(os.path.relpath(os.path.join(dimple_path,'prepared2.mtz')),xtal+'.free.mtz') -# db_dict['RefinementMTZfree']=os.path.realpath(xtal+'.free.mtz').replace(os.getcwd()+'/','') - db_dict['RefinementMTZfree']=os.path.realpath(xtal+'.free.mtz') -# db_dict['RefinementMTZfree']=xtal+'.free.mtz' - elif os.path.isfile(os.path.join(dimple_path,'prepared.mtz')): - os.symlink(os.path.relpath(os.path.join(dimple_path,'prepared.mtz')),xtal+'.free.mtz') - db_dict['RefinementMTZfree']=os.path.realpath(xtal+'.free.mtz') -# db_dict['RefinementMTZfree']=os.path.realpath(xtal+'.free.mtz').replace(os.getcwd()+'/','') -# db_dict['RefinementMTZfree']=xtal+'.free.mtz' - elif os.path.isfile(os.path.join(dimple_path,'free.mtz')): - os.symlink(os.path.relpath(os.path.join(dimple_path,'free.mtz')),xtal+'.free.mtz') - db_dict['RefinementMTZfree']=os.path.realpath(xtal+'.free.mtz') - - return db_dict - - - def sync_compound_information(self,db_dict): - # only update database if SMILES or compoundID field is blank! - - compoundID=db_dict['CompoundCode'] - if compoundID=='None' or compoundID=='': - if os.path.isdir('compound'): - for smiles in glob.glob('compound/*'): - if smiles.endswith('smiles'): - for line in open(smiles): - if len(line.split()) >= 1: - db_dict['CompoundCode']=smiles[smiles.rfind('/')+1:smiles.rfind('.')] - compoundID=db_dict['CompoundCode'] - break - - if os.path.isfile(compoundID+'.cif') and os.path.getsize(compoundID+'.cif') > 20: - db_dict['RefinementCIF']=os.path.realpath(compoundID+'.cif').replace(os.getcwd()+'/','') - db_dict['RefinementCIFStatus']='restraints generated' - else: - os.system('/bin/rm {0!s}.cif 2> /dev/null'.format(compoundID)) - os.system('/bin/rm compound/{0!s}.cif 2> /dev/null'.format(compoundID)) - db_dict['RefinementCIF']='' - db_dict['RefinementCIFStatus']='pending' - - smilesDB=db_dict['CompoundSMILES'] - smiles_found=True - if smilesDB=='None' or smilesDB=='': - smiles_found=False - if os.path.isdir('compound'): - for smiles in glob.glob('compound/*'): - if smiles.endswith('smiles'): - for line in open(smiles): - if len(line.split()) >= 1: - db_dict['CompoundSMILES']=line.split()[0] - smilesDB=db_dict['CompoundSMILES'] - smiles_found=True - break - - if not smiles_found: - db_dict['RefinementCIFStatus']='missing smiles' - - if not os.path.isfile(compoundID+'.pdb') or os.path.getsize(compoundID+'.pdb') < 20: - os.system('/bin/rm {0!s}.pdb 2> /dev/null'.format(compoundID)) - os.system('/bin/rm compound/{0!s}.pdb 2> /dev/null'.format(compoundID)) - - if not os.path.isfile(compoundID+'.png') or os.path.getsize(compoundID+'.png') < 20: - os.system('/bin/rm {0!s}.png 2> /dev/null'.format(compoundID)) - os.system('/bin/rm compound/{0!s}.png 2> /dev/null'.format(compoundID)) - - return db_dict - - - def sync_refinement_results(self,xtal,db_dict): - - # - # REFINE pdb - # - -# found_refine_pdb=self.find_file('refine.pdb',xtal) -# if found_refine_pdb and not 'dimple' in os.path.realpath('refine.pdb'): - -# if os.path.isfile('refine.pdb') and not 'dimple' in os.path.realpath('refine.pdb'): - if os.path.isfile('refine.pdb'): - db_dict['RefinementPDB_latest']=os.path.realpath('refine.pdb') -# db_dict['RefinementPDB_latest']=os.path.realpath('refine.pdb').replace(os.getcwd()+'/','') - db_dict['RefinementStatus']='finished' - pdb_info=parse().dict_for_datasource_update('refine.pdb') - db_dict.update(pdb_info) - if db_dict['RefinementOutcome']=='None' or db_dict['RefinementOutcome']=='': - db_dict['RefinementOutcome']='3 - In Refinement' - elif str(db_dict['RefinementOutcome']).startswith('1'): - db_dict['RefinementOutcome']='3 - In Refinement' - elif str(db_dict['RefinementOutcome']).startswith('2'): - db_dict['RefinementOutcome']='3 - In Refinement' - else: - db_dict['RefinementPDB_latest']='' - db_dict['RefinementStatus']='pending' - db_dict['RefinementOutcome']='1 - Analysis Pending' - os.system('/bin/rm refine.pdb 2> /dev/null') - - if os.path.isfile('REFINEMENT_IN_PROGRESS'): - db_dict['RefinementStatus']='running' - - # - # REFINE bound pdb - # - - if os.path.isfile('refine.split.bound-state.pdb'): - db_dict['RefinementBoundConformation']=os.path.realpath('refine.split.bound-state.pdb') -# db_dict['RefinementBoundConformation']='refine.bound.pdb' - else: -# if os.path.isfile('refine.pdb'): -# os.system("giant.strip_conformations pdb=refine.pdb suffix='.bound.pdb'") -# if os.path.isfile('refine.bound.pdb'): -# db_dict['RefinementBoundConformation']=os.path.realpath('refine.bound.pdb') -# else: -# db_dict['RefinementBoundConformation']='' -# else: -# db_dict['RefinementBoundConformation']='' - db_dict['RefinementBoundConformation']='' - - # - # REFINE mtz - # - -# found_refine_mtz=self.find_file('refine.mtz',xtal) -# if found_refine_mtz and not 'dimple' in os.path.realpath('refine.mtz'): -# if os.path.isfile('refine.mtz') and not 'dimple' in os.path.realpath('refine.mtz'): - if os.path.isfile('refine.mtz'): - db_dict['RefinementMTZ_latest']=os.path.realpath('refine.mtz') -# db_dict['RefinementMTZ_latest']=os.path.realpath('refine.mtz').replace(os.getcwd()+'/','') - else: - db_dict['RefinementMTZ_latest']='' - os.system('/bin/rm refine.mtz 2> /dev/null') - - return db_dict - - - def find_apo_structures_for_PanDDA(self,panddaPATH): - - # first check if structure is already present in DB and if so if all the - # information concur - - # need to update pandda directory for every exported structure so that - # we know where to look for the pandda.log file that contains the relevant information - - # update CrystalName_of_pandda_input in DB - - # in DB: update StructureType field accordingly - - # newer pandda versions seem to have severl copies of pandda.log with names like - # pandda-2016-09-01-2139.log - panddaLog=glob.glob(os.path.join(panddaPATH,'pandda*log')) - panddaLog.sort(key=os.path.getmtime) - - panddaVersion='unknown' - readindApoStructures = False - apoStructures = [] - apoStructureDict = {} - apoString='' - for files in panddaLog: - for line in open(files): - if line.startswith('- Pandda Version'): - if len(line.split()) >= 4: - panddaVersion=line.split()[3] - if 'No Statistical Maps Found:' in line: - readindApoStructures=True - if readindApoStructures: - if 'Pickling Object: processed_datasets' in line: - if line.split() >= 2: - # e.g. line.split() -> ['Pickling', 'Object:', 'processed_datasets/NUDT22A-x0055/pickles/dataset.pickle'] - xtal=line.split()[2].split('/')[1] - if os.path.isfile(os.path.join(panddaPATH,'processed_datasets',xtal,xtal+'-pandda-input.pdb')): - apoStructures.append(xtal) - apoString+=xtal+';' - if 'Pre-existing statistical maps (from previous runs) have been found and will be reused:' in line: - readindApoStructures=False - apoStructureDict[panddaPATH]=apoStructures - - return apoString[:-1] - -# def sync_pandda_table(self): -# progress_step=1 -# progress=0 -# self.emit(QtCore.SIGNAL('update_progress_bar'), progress) -# -# # also need to update PANDDA table... -# pandda_models=self.db.execute_statement("select CrystalName,PANDDA_site_index,PANDDA_site_event_index,PANDDA_site_x,PANDDA_site_y,PANDDA_site_z,PANDDApath,ApoStructures from panddaTable") -# if len(pandda_models) > 0: -# progress_step=100/float(len(pandda_models)) -# -# if pandda_models != []: -# for entry in pandda_models: -# db_pandda_dict={} -# xtal=entry[0] -# site_index=entry[1] -# event_index=entry[2] -# panddaPATH=entry[6] -# apoStructures=entry[7] -# self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'checking %s -> site %s -> event %s ' %(xtal,site_index,event_index)) -# try: -# event_x = float(str(entry[3])) -# event_y = float(str(entry[4])) -# event_z = float(str(entry[5])) -# except ValueError: -# pass -# -# # do not update pandda path since this one is updated during pandda export! -# # instead try to get apo semi-colon separated list of apo structures that were used to -# # calculate event maps; but only if field is blank! -## db_pandda_dict['PANDDApath']=self.panddas_directory -# if str(apoStructures)=='None' or apoStructures=='': -# if panddaPATH != 'None' or panddaPATH != '': -# self.Logfile.insert('trying to find which apo structures were used to calculate the event maps in '+panddaPATH) -# db_pandda_dict['ApoStructures']=self.find_apo_structures_for_PanDDA(panddaPATH) -# else: -# self.Logfile.insert('pandda path for '+xtal+' is empty in database') -# -# # event map -# -# found_event_map=False -# db_pandda_dict['PANDDA_site_event_map']='' -# for file in glob.glob(os.path.join(self.initial_model_directory,xtal,'*ccp4')): -# filename=file[file.rfind('/')+1:] -# if filename.startswith(xtal+'-event_'+event_index) and filename.endswith('map.native.ccp4'): -# event_map=file -# db_pandda_dict['PANDDA_site_event_map']=os.path.realpath(event_map) -## db_pandda_dict['PANDDA_site_event_map']=os.path.realpath(event_map).replace(os.getcwd()+'/','') -# found_event_map=True -# break -# if not found_event_map: -# db_pandda_dict['PANDDA_site_event_map']='' -# -# db_pandda_dict['PANDDA_site_initial_model']='' -# for file in glob.glob(os.path.join(self.initial_model_directory,xtal,'*pdb')): -# filename=file[file.rfind('/')+1:] -# if filename.endswith('-ensemble-model.pdb'): -# db_pandda_dict['PANDDA_site_initial_model']=os.path.realpath(file).replace(os.getcwd()+'/','') -# break -# -# db_pandda_dict['PANDDA_site_initial_mtz']='' -# for file in glob.glob(os.path.join(self.initial_model_directory,xtal,'*mtz')): -# filename=file[file.rfind('/')+1:] -# if filename.endswith('pandda-input.mtz'): -# db_pandda_dict['PANDDA_site_initial_mtz']=os.path.realpath(file).replace(os.getcwd()+'/','') -# break -# -# -# db_pandda_dict['PANDDA_site_ligand_resname'] = '' -# db_pandda_dict['PANDDA_site_ligand_chain'] = '' -# db_pandda_dict['PANDDA_site_ligand_sequence_number'] = '' -# db_pandda_dict['PANDDA_site_ligand_altLoc'] = '' -# db_pandda_dict['PANDDA_site_ligand_placed'] = 'False' -# db_pandda_dict['PANDDA_site_spider_plot'] = '' -# db_pandda_dict['PANDDA_site_ligand_id'] = '' -# -# db_pandda_dict['PANDDA_site_occupancy'] = '' -# db_pandda_dict['PANDDA_site_B_average'] = '' -# db_pandda_dict['PANDDA_site_B_ratio_residue_surroundings'] = '' -# db_pandda_dict['PANDDA_site_rmsd'] = '' -# db_pandda_dict['PANDDA_site_RSCC'] = '' -# db_pandda_dict['PANDDA_site_RSR'] = '' -# db_pandda_dict['PANDDA_site_RSZD'] = '' -# -# if os.path.isfile(os.path.join(self.initial_model_directory,xtal,'refine.pdb')): -# ligands_in_file=pdbtools(os.path.join(self.initial_model_directory,xtal,'refine.pdb')).find_xce_ligand_details() -# -# for ligand in ligands_in_file: -# residue_name= ligand[0] -# residue_chain= ligand[1] -# residue_number= ligand[2] -# residue_altLoc= ligand[3] -# residue_xyz = pdbtools(os.path.join(self.initial_model_directory,xtal,'refine.pdb')).get_center_of_gravity_of_residue_ish(residue_chain, residue_number) -# distance = misc().calculate_distance_between_coordinates(residue_xyz[0], residue_xyz[1],residue_xyz[2],event_x, event_y,event_z) -# # if coordinate of ligand and event are closer than 7A, then we assume they belong together -# if distance < 7: -# db_pandda_dict['PANDDA_site_ligand_resname'] = residue_name -# db_pandda_dict['PANDDA_site_ligand_chain'] = residue_chain -# db_pandda_dict['PANDDA_site_ligand_sequence_number'] = residue_number -# db_pandda_dict['PANDDA_site_ligand_altLoc'] = residue_altLoc -# db_pandda_dict['PANDDA_site_ligand_placed'] = 'True' -# db_pandda_dict['PANDDA_site_ligand_id']=residue_name+'-'+residue_chain+'-'+residue_number -# -# if xtal+'/Refine_' in os.path.realpath(os.path.join(self.initial_model_directory,xtal,'refine.pdb')): -# tmp=os.path.realpath(os.path.join(self.initial_model_directory,xtal,'refine.pdb')) -# spider_plot=os.path.join(tmp[:tmp.rfind('/')],'residue_plots',residue_name+'-'+residue_chain+'-'+residue_number+'.png') -# if os.path.isfile(spider_plot): -# db_pandda_dict['PANDDA_site_spider_plot']=os.path.realpath(spider_plot) -## db_pandda_dict['PANDDA_site_spider_plot']=os.path.realpath(spider_plot).replace(os.getcwd()+'/','') -# if os.path.isfile(os.path.join(tmp[:tmp.rfind('/')],'residue_scores.csv')): -# -# with open(os.path.join(tmp[:tmp.rfind('/')],'residue_scores.csv'), 'rb') as csv_import: -# csv_dict = csv.DictReader(csv_import) -# for i, line in enumerate(csv_dict): -# residueNameChainNumber = line[''] -# if residueNameChainNumber == residue_name+'-'+residue_chain+'-'+residue_number: -# db_pandda_dict['PANDDA_site_occupancy'] = line['Occupancy'] -# db_pandda_dict['PANDDA_site_B_average'] = line['Average B-factor (Residue)'] -# db_pandda_dict['PANDDA_site_B_ratio_residue_surroundings'] = line['Surroundings B-factor Ratio'] -# db_pandda_dict['PANDDA_site_rmsd'] = line['Model RMSD'] -# db_pandda_dict['PANDDA_site_RSCC'] = line['RSCC'] -# db_pandda_dict['PANDDA_site_RSR'] = line['RSR'] -# db_pandda_dict['PANDDA_site_RSZD'] = line['RSZD'] -# break -# -# if db_pandda_dict != {}: -## self.db.update_panddaTable(xtal, site_index, db_pandda_dict) -# self.db.update_site_event_panddaTable(xtal, site_index, event_index, db_pandda_dict) -# self.Logfile.insert('updating panddaTable for xtal: %s, site: %s' %(xtal,site_index)) -# -# progress += progress_step -# self.emit(QtCore.SIGNAL('update_progress_bar'), progress) -# - - - def sync_pandda_table_NEW(self): - progress_step=1 - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - # also need to update PANDDA table... - pandda_models=self.db.execute_statement("select CrystalName,PANDDA_site_index,PANDDA_site_event_index,PANDDA_site_x,PANDDA_site_y,PANDDA_site_z,PANDDApath,ApoStructures from panddaTable") - if len(pandda_models) > 0: - progress_step=100/float(len(pandda_models)) - else: - self.Logfile.warning('panddaTable seems to be empty!') - - if pandda_models: - for entry in pandda_models: - db_pandda_dict={} - xtal=entry[0] - site_index=entry[1] - event_index=entry[2] - panddaPATH=entry[6] - apoStructures=entry[7] - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'checking {0!s} -> site {1!s} -> event {2!s} '.format(xtal, site_index, event_index)) - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - progress += progress_step - - try: - event_x = float(str(entry[3])) - event_y = float(str(entry[4])) - event_z = float(str(entry[5])) - except ValueError: - pass - - # do not update pandda path since this one is updated during pandda export! - # instead try to get apo semi-colon separated list of apo structures that were used to - # calculate event maps; but only if field is blank! -# db_pandda_dict['PANDDApath']=self.panddas_directory - if str(apoStructures)=='None' or apoStructures=='': - if panddaPATH != 'None' or panddaPATH != '': - self.Logfile.insert('trying to find which apo structures were used to calculate the event maps in '+panddaPATH) - db_pandda_dict['ApoStructures']=self.find_apo_structures_for_PanDDA(panddaPATH) - else: - self.Logfile.insert('pandda path for '+xtal+' is empty in database') - - # event map - - found_event_map=False - db_pandda_dict['PANDDA_site_event_map']='' - for file in glob.glob(os.path.join(self.initial_model_directory,xtal,'*ccp4')): - filename=file[file.rfind('/')+1:] - if filename.startswith(xtal+'-event_'+event_index) and filename.endswith('map.native.ccp4'): - event_map=file - db_pandda_dict['PANDDA_site_event_map']=os.path.realpath(event_map) -# db_pandda_dict['PANDDA_site_event_map']=os.path.realpath(event_map).replace(os.getcwd()+'/','') - found_event_map=True - break - if not found_event_map: - db_pandda_dict['PANDDA_site_event_map']='' - - db_pandda_dict['PANDDA_site_initial_model']='' - for file in glob.glob(os.path.join(self.initial_model_directory,xtal,'*pdb')): - filename=file[file.rfind('/')+1:] - if filename.endswith('-ensemble-model.pdb'): - db_pandda_dict['PANDDA_site_initial_model']=os.path.realpath(file).replace(os.getcwd()+'/','') - break - - db_pandda_dict['PANDDA_site_initial_mtz']='' - for file in glob.glob(os.path.join(self.initial_model_directory,xtal,'*mtz')): - filename=file[file.rfind('/')+1:] - if filename.endswith('pandda-input.mtz'): - db_pandda_dict['PANDDA_site_initial_mtz']=os.path.realpath(file).replace(os.getcwd()+'/','') - break - - - db_pandda_dict['PANDDA_site_ligand_resname'] = '' - db_pandda_dict['PANDDA_site_ligand_chain'] = '' - db_pandda_dict['PANDDA_site_ligand_sequence_number'] = '' - db_pandda_dict['PANDDA_site_ligand_altLoc'] = '' - db_pandda_dict['PANDDA_site_ligand_placed'] = 'False' - db_pandda_dict['PANDDA_site_spider_plot'] = '' - db_pandda_dict['PANDDA_site_ligand_id'] = '' - - db_pandda_dict['PANDDA_site_occupancy'] = '' - db_pandda_dict['PANDDA_site_B_average'] = '' - db_pandda_dict['PANDDA_site_B_ratio_residue_surroundings'] = '' - db_pandda_dict['PANDDA_site_rmsd'] = '' - db_pandda_dict['PANDDA_site_RSCC'] = '' - db_pandda_dict['PANDDA_site_RSR'] = '' - db_pandda_dict['PANDDA_site_RSZD'] = '' - - if os.path.isfile(os.path.join(self.initial_model_directory,xtal,'refine.pdb')): - ligands_in_file=pdbtools(os.path.join(self.initial_model_directory,xtal,'refine.pdb')).find_xce_ligand_details() - if not ligands_in_file: - self.Logfile.warning('{0!s}: could not find any ligands in refine.pdb'.format(xtal)) - continue - else: - self.Logfile.insert('{0!s}: found the following ligands in refine.pdb: {1!s}'.format(xtal, str(ligands_in_file))) - - distanceList=[] - for ligand in ligands_in_file: - residue_name= ligand[0] - residue_chain= ligand[1] - residue_number= ligand[2] - residue_altLoc= ligand[3] - residue_xyz = pdbtools(os.path.join(self.initial_model_directory,xtal,'refine.pdb')).get_center_of_gravity_of_residue_ish(residue_chain, residue_number) - distance = misc().calculate_distance_between_coordinates(residue_xyz[0], residue_xyz[1],residue_xyz[2],event_x, event_y,event_z) - distanceList.append([distance,residue_name,residue_chain,residue_number,residue_altLoc]) - self.Logfile.insert('{0!s}: calculating distance between event and ligand ({1!s} {2!s} {3!s}): {4!s}'.format(xtal, residue_name, residue_chain, residue_number, str(distance))) - - # now take the ligand that is closest to the event - try: - smallestDistance = min(distanceList, key=lambda x: x[0]) - except ValueError: - self.Logfile.error('could not determine smallest distance between current ligand pandda events') - continue - distance = smallestDistance[0] - residue_name = smallestDistance[1] - residue_chain = smallestDistance[2] - residue_number = smallestDistance[3] - residue_altLoc = smallestDistance[4] - self.Logfile.insert('{0!s}: ligand with the shorted distance ({1!s}A) to the current event (id: {2!s}): {3!s} {4!s} {5!s} {6!s}'.format(xtal, str(distance), event_index, residue_name, residue_chain, residue_number, residue_altLoc)) - db_pandda_dict['PANDDA_site_ligand_resname'] = residue_name - db_pandda_dict['PANDDA_site_ligand_chain'] = residue_chain - db_pandda_dict['PANDDA_site_ligand_sequence_number'] = residue_number - db_pandda_dict['PANDDA_site_ligand_altLoc'] = residue_altLoc - db_pandda_dict['PANDDA_site_ligand_placed'] = 'True' - db_pandda_dict['PANDDA_site_ligand_id']=residue_name+'-'+residue_chain+'-'+residue_number - - if xtal+'/Refine_' in os.path.realpath(os.path.join(self.initial_model_directory,xtal,'refine.pdb')): - tmp=os.path.realpath(os.path.join(self.initial_model_directory,xtal,'refine.pdb')) - spider_plot=os.path.join(tmp[:tmp.rfind('/')],'residue_plots',residue_chain+'-'+residue_number+'.png').replace(' ','') - if os.path.isfile(spider_plot): - db_pandda_dict['PANDDA_site_spider_plot']=os.path.realpath(spider_plot) - if os.path.isfile(os.path.join(tmp[:tmp.rfind('/')],'residue_scores.csv')): - with open(os.path.join(tmp[:tmp.rfind('/')],'residue_scores.csv'), 'rb') as csv_import: - csv_dict = csv.DictReader(csv_import) - for i, line in enumerate(csv_dict): - residueNameChainNumber = line[''] - if residueNameChainNumber == residue_chain+'-'+residue_number: - db_pandda_dict['PANDDA_site_occupancy'] = line['Occupancy'] - db_pandda_dict['PANDDA_site_B_average'] = line['Average B-factor (Residue)'] - db_pandda_dict['PANDDA_site_B_ratio_residue_surroundings'] = line['Surroundings B-factor Ratio'] - db_pandda_dict['PANDDA_site_rmsd'] = line['Model RMSD'] - db_pandda_dict['PANDDA_site_RSCC'] = line['RSCC'] - db_pandda_dict['PANDDA_site_RSR'] = line['RSR'] - db_pandda_dict['PANDDA_site_RSZD'] = line['RSZD'] -# break - - if db_pandda_dict != {}: -# self.db.update_panddaTable(xtal, site_index, db_pandda_dict) - self.db.update_site_event_panddaTable(xtal, site_index, event_index, db_pandda_dict) - self.Logfile.insert('updating panddaTable for xtal: {0!s}, site: {1!s}, event: {2!s}'.format(xtal, site_index,event_index)) - self.Logfile.insert('-> panddaDict: ' + str(db_pandda_dict)) - -# progress += progress_step -# self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - - - - -class create_png_and_cif_of_compound(QtCore.QThread): - def __init__(self,external_software,initial_model_directory,compound_list,database_directory,data_source_file,todo,ccp4_scratch_directory,xce_logfile,max_queue_jobs,restraints_program): - QtCore.QThread.__init__(self) - self.external_software=external_software - self.initial_model_directory=initial_model_directory - self.compound_list=compound_list - self.database_directory=database_directory - self.data_source_file=data_source_file - self.todo=todo - self.ccp4_scratch_directory=ccp4_scratch_directory - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.max_queue_jobs=max_queue_jobs - self.db=XChemDB.data_source(os.path.join(self.database_directory,self.data_source_file)) - self.restraints_program=restraints_program - - def run(self): - # first remove all ACEDRG input scripts in ccp4_scratch directory - self.Logfile.insert('removing all xce_acedrg scripts from '+self.ccp4_scratch_directory) - os.chdir(self.ccp4_scratch_directory) - os.system('/bin/rm -f xce_acedrg*') - - progress_step=100/float(len(self.compound_list)) - progress=0 - counter=1 - for item in self.compound_list: - sampleID=item[0] - compoundID=item[1] - sm=item[2] - # if counterions are present, split and take the longest string in list - smiles = max(sm.split('.'), key=len) - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'creating ACEDRG shell script for '+sampleID) - if compoundID=='' or compoundID is None: - compoundID='compound' - - if not os.path.isdir(os.path.join(self.initial_model_directory,sampleID)): - os.mkdir(os.path.join(self.initial_model_directory,sampleID)) - - if self.todo=='ALL' or self.todo=='SELECTED': - # remove symbolic links if present - if os.path.isfile(os.path.join(self.initial_model_directory,sampleID,compoundID.replace(' ','')+'.pdb')): - os.system('/bin/rm '+os.path.join(self.initial_model_directory,sampleID,compoundID.replace(' ','')+'.pdb')) -# commented this out since people found the presence of the old.cif file interfering with pandda.inspect -# if os.path.isfile(os.path.join(self.initial_model_directory,sampleID,compoundID.replace(' ','')+'.cif')): -# # copy existing CIF file to old.cif so that it can be used as input in -# # restraints generating program -# os.chdir(os.path.join(self.initial_model_directory,sampleID)) -# os.system('/bin/cp %s old.cif' %(compoundID.replace(' ','')+'.cif')) -# os.system('/bin/rm '+os.path.join(self.initial_model_directory,sampleID,compoundID.replace(' ','')+'.cif')) - if os.path.isfile(os.path.join(self.initial_model_directory,sampleID,compoundID.replace(' ','')+'.png')): - os.system('/bin/rm '+os.path.join(self.initial_model_directory,sampleID,compoundID.replace(' ','')+'.png')) - if os.path.isdir(os.path.join(self.initial_model_directory,sampleID,'compound')): - os.system('/bin/rm -fr '+os.path.join(self.initial_model_directory,sampleID,'compound')) - db_dict= {'RefinementCIFStatus': 'pending'} - self.Logfile.insert('{0!s}: removed compound directory and all its contents'.format(sampleID)) - self.Logfile.insert('{0!s}: setting RefinementCIFStatus flag to started'.format(sampleID)) - self.db.update_data_source(sampleID,db_dict) - - # create 'compound' directory if not present - if not os.path.isdir(os.path.join(self.initial_model_directory,sampleID,'compound')): - os.mkdir(os.path.join(self.initial_model_directory,sampleID,'compound')) - - # create text file which contains the smiles string - if not os.path.isfile(os.path.join(self.initial_model_directory,sampleID,'compound',compoundID+'.smiles')): - os.chdir(os.path.join(self.initial_model_directory,sampleID,'compound')) - f=open(compoundID+'.smiles','w') - f.write(smiles) - f.close() - - if not os.path.isfile(os.path.join(self.initial_model_directory,sampleID,compoundID.replace(' ','')+'.cif')) \ - or self.todo=='SELECTED': - os.chdir(os.path.join(self.initial_model_directory,sampleID)) - os.system('/bin/rm -f %s*' %compoundID.replace(' ','')) - os.chdir(os.path.join(self.initial_model_directory,sampleID,'compound')) - - - helpers().make_png( self.initial_model_directory, - sampleID, - compoundID, - smiles, - self.external_software, - self.database_directory, - self.data_source_file, - self.ccp4_scratch_directory, - counter, - self.xce_logfile, - self.restraints_program ) - counter += 1 - - db_dict= {'RefinementCIFprogram': self.restraints_program, 'RefinementCIFStatus': 'started'} - self.Logfile.insert('{0!s}: setting RefinementCIFStatus flag to started'.format(sampleID)) - self.db.update_data_source(sampleID,db_dict) - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - # submit array job at Diamond - self.Logfile.insert('created input scripts for '+str(counter)+' ACEDRG jobs in '+self.ccp4_scratch_directory) - os.chdir(self.ccp4_scratch_directory) - self.Logfile.insert('changing directory to '+self.ccp4_scratch_directory) - if counter > 1: -# if os.getcwd().startswith('/dls'): - if os.path.isdir('/dls'): - if self.external_software['qsub_array']: - Cmds = ( - '#PBS -joe -N xce_acedrg_master\n' - './xce_acedrg_$SGE_TASK_ID.sh\n' - ) - f = open('acedrg_master.sh','w') - f.write(Cmds) - f.close() - self.Logfile.insert('submitting array job with maximal 100 jobs running on cluster') - self.Logfile.insert('using the following command:') - self.Logfile.insert(' qsub -P labxchem -q medium.q -t 1:{0!s} -tc {1!s} acedrg_master.sh'.format(str(counter), self.max_queue_jobs)) - os.system('qsub -P labxchem -q medium.q -t 1:{0!s} -tc {1!s} -N acedrg acedrg_master.sh'.format(str(counter), self.max_queue_jobs)) - else: - self.Logfile.insert("cannot start ARRAY job: make sure that 'module load global/cluster' is in your .bashrc or .cshrc file") - elif self.external_software['qsub']: - self.Logfile.insert('submitting {0!s} individual jobs to cluster'.format((str(counter)))) - self.Logfile.insert('WARNING: this could potentially lead to a crash...') - for i in range(counter): - self.Logfile.insert('qsub -q medium.q -N acedrg xce_acedrg_{0!s}.sh'.format((str(i+1)))) - os.system('qsub -N acedrg xce_acedrg_{0!s}.sh'.format((str(i+1)))) - else: - self.Logfile.insert('running %s consecutive ACEDRG jobs on your local machine') - for i in range(counter): - self.Logfile.insert('starting xce_acedrg_{0!s}.sh'.format((str(i+1)))) - os.system('./xce_acedrg_{0!s}.sh'.format((str(i+1)))) - -# self.emit(QtCore.SIGNAL("finished()")) - self.emit(QtCore.SIGNAL('datasource_menu_reload_samples')) - - - -class fit_ligands(QtCore.QThread): - def __init__(self,external_software,initial_model_directory,compound_list,database_directory,data_source_file,ccp4_scratch_directory,xce_logfile,max_queue_jobs): - QtCore.QThread.__init__(self) - self.external_software=external_software - self.queueing_system_available = external_software['qsub'] - self.initial_model_directory=initial_model_directory - self.compound_list=compound_list - self.database_directory=database_directory - self.data_source_file=data_source_file - self.ccp4_scratch_directory=ccp4_scratch_directory - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.max_queue_jobs=max_queue_jobs - self.db=XChemDB.data_source(os.path.join(self.database_directory,self.data_source_file)) - self.n = 1 - - def prepareInput(self,cmd,ligList): - for cif in ligList: - cmd += 'rhofit -m ../init.mtz -p ../init.pdb -l ../compound/%s.cif -d %s_rhofit\n' %(cif,cif) - cmd += 'phenix.ligandfit data=../init.mtz model=../init.pdb ligand=../compound/%s.cif clean_up=True\n' %cif - cmd += '/bin/mv LigandFit_run_1_ %s_phenix\n' %cif - cmd += '/bin/rm -fr PDS\n\n' - return cmd - # rhofit -m refine.mtz -p refine.pdb -l ../compound/NU074105a.cif -d NU074105a_rhofit - # phenix.ligandfit data=refine.mtz model=refine.pdb ligand=../compound/NU074105a.cif - # phenix.get_cc_mtz_pdb LigandFit_run_1_/ligand_fit_1_1.pdb refine.mtz > log - # grep 'local CC:' log - - def get_header(self,sampleID): - if self.queueing_system_available: - top_line = '#PBS -joe -N XCE_dimple\n' - else: - top_line = '#!' + os.getenv('SHELL') + '\n' - - cmd = ( - '{0!s}\n'.format(top_line)+ - '\n' - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,sampleID,'autofit_ligand') + - '\n' - ) - - return cmd - - def get_footer(self,cmd,sampleID,compoundID): - cmd += ('$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/find_best_fitting_ligand.py {0!s} {1!s} {2!s}' - .format(compoundID.replace(' ', ''), os.path.join(self.initial_model_directory, sampleID), - os.path.join(self.database_directory, self.data_source_file)) ) - return cmd - - def run(self): - # first remove all ACEDRG input scripts in ccp4_scratch directory - self.Logfile.insert('removing all xce_fit_ligands scripts from '+self.ccp4_scratch_directory) - os.chdir(self.ccp4_scratch_directory) - os.system('/bin/rm -f xce_autofit_ligand*') - - progress_step=100/float(len(self.compound_list)) - progress=0 - counter=1 - for item in self.compound_list: - sampleID=item[0] - compoundID=item[1] - - if os.path.isdir(os.path.join(self.initial_model_directory, sampleID, 'autofit_ligand')): - os.system('/bin/rm -fr ' + os.path.join(self.initial_model_directory, sampleID, 'autofit_ligand')) - os.mkdir(os.path.join(self.initial_model_directory, sampleID, 'autofit_ligand')) - - # find ligands to fit (there might be more than one in case of stereoisomers - ligList = [] - for file in glob.glob(os.path.join(self.initial_model_directory, sampleID, 'compound',compoundID+'*.cif')): - cif = file[file.rfind('/')+1:].replace('.cif','') - if 'with_H' in cif: - continue - else: - ligList.append(cif) - - if ligList != []: - cmd = self.get_header(sampleID) - cmd = self.prepareInput(cmd,ligList) - cmd = self.get_footer(cmd, sampleID, compoundID) - self.write_script(cmd) - self.run_script() - self.n += 1 - - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - # self.emit(QtCore.SIGNAL("finished()")) - self.emit(QtCore.SIGNAL('datasource_menu_reload_samples')) - - def write_script(self,cmd): - os.chdir(self.ccp4_scratch_directory) - f = open('xce_autofit_ligand_{0!s}.sh'.format(str(self.n)), 'w') - f.write(cmd) - f.close() - os.system('chmod +x xce_autofit_ligand_{0!s}.sh'.format(str(self.n))) - - def run_script(self): - # submit job - self.Logfile.insert('created input scripts for ' + str(self.n) + ' in ' + self.ccp4_scratch_directory) - os.chdir(self.ccp4_scratch_directory) - if os.path.isdir('/dls'): - if self.external_software['qsub_array']: - Cmds = ( - '#PBS -joe -N xce_autofit_ligand_master\n' + - './xce_autofit_ligand_$SGE_TASK_ID.sh\n' - ) - f = open('autofit_ligand_master.sh', 'w') - f.write(Cmds) - f.close() - self.Logfile.insert('submitting array job with maximal 100 jobs running on cluster') - self.Logfile.insert('using the following command:') - self.Logfile.insert( - 'qsub -P labxchem -q medium.q -t 1:{0!s} -tc {1!s} autofit_ligand_master.sh'.format(str(self.n), - self.max_queue_jobs)) - os.system( - 'qsub -P labxchem -q medium.q -t 1:{0!s} -tc {1!s} autofit_ligand_master.sh'.format(str(self.n - 1), - self.max_queue_jobs)) - else: - self.Logfile.insert( - "cannot start ARRAY job: make sure that 'module load global/cluster' is in your .bashrc or .cshrc file") - elif self.external_software['qsub']: - self.Logfile.insert('submitting {0!s} individual jobs to cluster'.format((str(self.n)))) - self.Logfile.insert('WARNING: this could potentially lead to a crash...') - for i in range(1, self.n): - self.Logfile.insert('qsub -q medium.q xce_autofit_ligand_{0!s}.sh'.format(str(i))) - os.system('qsub -q medium.q xce_autofit_ligand_{0!s}.sh'.format(str(i))) - else: - self.Logfile.insert( - 'running {0!s} consecutive autofit_ligand jobs on your local machine'.format(str(self.n - 1))) - for i in range(1, self.n+1): - self.Logfile.insert('starting xce_autofit_ligand_{0!s}.sh'.format(str(i))) - os.system('./xce_autofit_ligand_{0!s}.sh'.format(str(i))) - - - - - - - - - - - - - - -class merge_cif_files(QtCore.QThread): - def __init__(self,initial_model_directory,xce_logfile,second_cif_file,compound_list,todo): - QtCore.QThread.__init__(self) - self.initial_model_directory=initial_model_directory - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.second_cif_file = second_cif_file - self.compound_list=compound_list - self.todo=todo - - def run(self): - progress_step=100/float(len(self.compound_list)) - progress=0 - counter=1 - - for item in self.compound_list: - sampleID=item[0] - compoundID=item[1] - - if os.path.isfile(os.path.join(self.initial_model_directory, sampleID, 'compound', compoundID + '.cif')): - self.Logfile.insert('%s: found %s.cif file in compound sub-directory' % (sampleID, compoundID)) - else: - self.Logfile.error( - '%s: %s.cif file does not exist in compound sub-directory; skipping...' % (sampleID, compoundID)) - continue - - os.chdir(os.path.join(self.initial_model_directory,sampleID)) - if os.path.isfile(os.path.join(self.initial_model_directory,sampleID,compoundID+'.cif')): - self.Logfile.warning('%s: removing symbolic link to (or file) %s.cif from sample directory' %(sampleID,compoundID)) - os.system('/bin/rm %s.cif 2> /dev/null' %compoundID) - - if self.todo == 'merge': - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), sampleID+' merging CIF files') - - self.run_libcheck(sampleID,compoundID) - - elif self.todo == 'restore': - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), sampleID + ' restoring original CIF file') - self.Logfile.insert('%s: restoring symbolic link -> ln -s compound/%s.cif .' %(sampleID,compoundID)) - os.system('ln -s compound/%s.cif .' %compoundID) - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL("finished()")) - - def run_libcheck(self,sampleID,compoundID): - cmd = ( - '#!/bin/bash\n' - '\n' - '$CCP4/bin/libcheck << eof \n' - '_Y\n' - '_FILE_L compound/%s.cif\n' %compoundID+ - '_FILE_L2 '+self.second_cif_file+'\n' - '_FILE_O '+compoundID+'.cif\n' - '_END\n' - 'eof\n' - ) - self.Logfile.insert('%s: running libcheck with the following input:\n%s' %(sampleID,cmd)) - os.system(cmd) - if os.path.isfile(compoundID+'.cif.lib'): - self.Logfile.insert('%s: merged CIF file successfully created' %sampleID) - os.system('/bin/mv %s %s' %(compoundID+'.cif.lib',compoundID+'.cif')) - else: - self.Logfile.error('%s: could not create merged CIF file' %sampleID) - self.Logfile.warning('%s: will re-create symbolic links to original restraints file' %sampleID) - os.system('ln -s compound/%s.cif .' %compoundID) - - - - - - -class run_dimple_on_all_autoprocessing_files(QtCore.QThread): - def __init__(self,sample_list,initial_model_directory,external_software,ccp4_scratch_directory,database_directory, - data_source_file,max_queue_jobs,xce_logfile, remote_submission, remote_submission_string, - dimple_twin_mode,pipeline): - QtCore.QThread.__init__(self) - self.sample_list=sample_list - self.initial_model_directory=initial_model_directory - self.external_software=external_software - self.queueing_system_available=external_software['qsub'] - self.ccp4_scratch_directory=ccp4_scratch_directory - self.database_directory=database_directory - self.data_source_file=data_source_file - self.max_queue_jobs=max_queue_jobs - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.pipeline=pipeline - self.using_remote_qsub_submission = remote_submission - self.remote_qsub_submission = remote_submission_string - self.dimple_twin_mode = dimple_twin_mode - - - def run(self): - progress_step=1 - if len(self.sample_list) != 0: - progress_step=100/float(len(self.sample_list)) - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - os.chdir(self.ccp4_scratch_directory) - os.system('/bin/rm -f xce_dimple*sh') - - db=XChemDB.data_source(os.path.join(self.database_directory,self.data_source_file)) - database=os.path.join(self.database_directory,self.data_source_file) - -# print(self.sample_list) - - for n,item in enumerate(self.sample_list): - - xtal = item[0] - visit_run_autoproc = item[1] - mtzin = item[2] - ref_pdb = item[3] - ref_mtz = item[4] - ref_cif = item[5] - - # check if reference mtzfile has an Rfree column; if not, then ignore - # DIMPLE assumes an Rfree column and barfs if it is not present - # note: ref_mtz looks like this: ref mtz -R reference.mtz -# if os.path.isfile(ref_mtz.split()[len(ref_mtz.split())-1]): -# mtz_column_dict=mtztools(ref_mtz.split()[len(ref_mtz.split())-1]).get_all_columns_as_dict() - if os.path.isfile(ref_mtz): - if 'FreeR_flag' not in mtz.object(ref_mtz).column_labels(): -# mtz_column_dict=mtztools(ref_mtz).get_all_columns_as_dict() -# if 'FreeR_flag' not in mtz_column_dict['RFREE']: - self.Logfile.insert('cannot find FreeR_flag in reference mtz file: {0!s} -> ignoring reference mtzfile!!!'.format(ref_mtz)) - ref_mtz = '' -# if mtz_column_dict['RFREE'] != []: -# self.Logfile.insert('found Rfree set with other column name though: {0!s}'.format(str(mtz_column_dict['RFREE']))) -# self.Logfile.insert('try renaming Rfree column to FreeR_flag with CAD!') - -# uniqueify = '' -# if 'FreeR_flag' in mtz.object(mtzin).column_labels(): -# uniqueify = 'uniqueify -f FreeR_flag ' + mtzin + ' ' + xtal + '-unique.mtz' + '\n' -# else: -# uniqueify = 'uniqueify ' + mtzin + ' ' + xtal + '-unique.mtz' + '\n' - - db_dict= {'DimpleReferencePDB': ref_pdb} - db.update_data_source(xtal,db_dict) - - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'creating input script for '+xtal+' in '+visit_run_autoproc) - - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): - os.mkdir(os.path.join(self.initial_model_directory,xtal)) - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'dimple')): - os.mkdir(os.path.join(self.initial_model_directory,xtal,'dimple')) - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc)): - os.mkdir(os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc)) - os.chdir(os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc)) - os.system('touch dimple_run_in_progress') - os.system('/bin/rm final.mtz 2> /dev/null') - os.system('/bin/rm final.pdb 2> /dev/null') - - if self.queueing_system_available: - top_line='#PBS -joe -N XCE_dimple\n' - else: - top_line='#!'+os.getenv('SHELL')+'\n' - - if 'csh' in os.getenv('SHELL'): - ccp4_scratch='setenv CCP4_SCR '+self.ccp4_scratch_directory+'\n' - elif 'bash' in os.getenv('SHELL'): - ccp4_scratch='export CCP4_SCR='+self.ccp4_scratch_directory+'\n' - else: - ccp4_scratch='' - - if 'dimple_rerun_on_selected_file' in visit_run_autoproc: - additional_cmds = ( - 'cd {0!s}\n'.format(os.path.join(self.initial_model_directory,xtal)) + - '/bin/rm dimple.pdb\n' - 'ln -s dimple/dimple_rerun_on_selected_file/dimple/final.pdb dimple.pdb\n' - '/bin/rm dimple.mtz\n' - 'ln -s dimple/dimple_rerun_on_selected_file/dimple/final.mtz dimple.mtz\n' - '/bin/rm 2fofc.map\n' - 'ln -s dimple/dimple_rerun_on_selected_file/dimple/2fofc.map .\n' - '/bin/rm fofc.map\n' - 'ln -s dimple/dimple_rerun_on_selected_file/dimple/fofc.map .\n' - '\n' - '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_for_new_dimple_pdb.py')+ - ' {0!s} {1!s} {2!s}\n'.format(os.path.join(self.database_directory,self.data_source_file), xtal, self.initial_model_directory) ) - - else: - additional_cmds='' - -# resolution_high = 0.1 -# o = iotbx.mtz.object(mtzin) -# low, high = o.max_min_resolution() - hkl = any_reflection_file(file_name=mtzin) - miller_arrays = hkl.as_miller_arrays() - mtzFile = miller_arrays[0] - - if mtzFile.space_group_info().symbol_and_number() == 'R 3 :H (No. 146)': - symNoAbsence = 'H3' - else: - symNoAbsence = str([x[0] for x in str(mtzFile.space_group_info().symbol_and_number().split('(')[0]).split()]).replace('[','').replace(']','').replace("'","").replace(',','').replace(' ','') - - dls_stuff = '' - if os.path.isdir('/dls'): - dls_stuff = ( - 'module unload ccp4\n' - 'source /dls/science/groups/i04-1/software/pandda_0.2.12/ccp4/ccp4-7.0/bin/ccp4.setup-sh\n' - ) - - twin = '' - if self.dimple_twin_mode: - twin = "--refmac-key 'TWIN'" - - Cmds = ( - '{0!s}\n'.format(top_line)+ - '\n' - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc) + - '\n' - 'source $XChemExplorer_DIR/setup-scripts/xce.setup-sh\n' - '\n' - + dls_stuff + - '\n' - + ccp4_scratch + - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py %s %s %s %s\n' %(database,xtal,'DimpleStatus','running') + - '\n' - 'unique hklout unique.mtz << eof\n' - ' cell %s\n' %str([round(float(i),2) for i in mtzFile.unit_cell().parameters()]).replace('[','').replace(']','')+ - ' symmetry %s\n' %symNoAbsence+ - ' resolution %s\n' %str(round(float(mtzFile.d_min()),3))+ - 'eof\n' - '\n' -# 'freerflag hklin unique.mtz hklout free.mtz > freerflag.log\n' - '\n' - 'sftools << eof > sftools.log\n' - ' read unique.mtz\n' - ' calc col F = 10.0\n' - ' calc col SIGF = 1.0\n' - ' write sftools.mtz\n' - 'eof\n' - '\n' - 'cad hklin1 sftools.mtz hklin2 %s hklout %s.999A.mtz << eof\n' %(mtzin,xtal) + - ' monitor BRIEF\n' - ' labin file 1 E1=F E2=SIGF\n' - ' labout file 1 E1=F_unique E2=SIGF_unique\n' - ' labin file 2 ALL\n' - ' resolution file 1 999.0 %s\n' %str(round(float(mtzFile.d_min()),2))+ - 'eof\n' - '\n' - "dimple --no-cleanup %s.999A.mtz %s %s %s %s dimple\n" %(xtal,ref_pdb,ref_mtz,ref_cif,twin) + - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal,'dimple',visit_run_autoproc,'dimple') + -# + uniqueify + -# '\n' -# 'cad hklin1 %s hklout %s < ignoring reference mtzfile!!!' %ref_mtz) -# ref_mtz = '' -# if mtz_column_dict['RFREE'] != []: -# self.Logfile.insert('found Rfree set with other column name though: %s' %str(mtz_column_dict['RFREE'])) -# self.Logfile.insert('try renaming Rfree column to FreeR_flag with CAD!') -# -# db_dict={} -# db_dict['DimpleReferencePDB']=ref_pdb -# self.db.update_data_source(xtal,db_dict) -# -# self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'creating input script for '+xtal+' in '+visit_run_autoproc) -# - - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): - os.mkdir(os.path.join(self.initial_model_directory,xtal)) - os.chdir(os.path.join(self.initial_model_directory,xtal)) - if os.path.isdir(os.path.join(self.initial_model_directory,xtal,'phenix.ligand_pipeline')): - os.system('/bin/rm -fr phenix.ligand_pipeline') - os.mkdir(os.path.join(self.initial_model_directory,xtal,'phenix.ligand_pipeline')) - os.system('touch phenix.ligand_pipeline_run_in_progress') - - if self.queueing_system_available: - top_line='#PBS -joe -N XCE_{0!s}\n'.format(self.pipeline) - else: - top_line='#!'+os.getenv('SHELL')+'\n' - - if 'csh' in os.getenv('SHELL'): - ccp4_scratch='setenv CCP4_SCR '+self.ccp4_scratch_directory+'\n' - elif 'bash' in os.getenv('SHELL'): - ccp4_scratch='export CCP4_SCR='+self.ccp4_scratch_directory+'\n' - else: - ccp4_scratch='' - - if os.path.isdir('/dls'): - ccp4_scratch+='module load phenix\n' - ccp4_scratch+='module load ccp4\n' - - mtz_column_list=mtztools(mtzin).get_all_columns_as_list() - rfree = '' - if 'FreeR_flag' in mtz_column_list: - rfree = ' xray_data.r_free_flags.label="FreeR_flag"' - - Cmds = ( - '{0!s}\n'.format(top_line)+ - '\n' - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal,'phenix.ligand_pipeline') + - '\n' - 'source $XChemExplorer_DIR/setup-scripts/xce.setup-sh\n' - '\n' - +ccp4_scratch+ - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py %s %s %s %s\n' %(os.path.join(self.database_directory,self.data_source_file),xtal,'DimpleStatus','running') + - '\n' - 'phenix.ligand_pipeline %s %s' %(ref_pdb,mtzin)+ - ' mr=False' - ' ligand_copies=0' - ' build=False' - ' prune=False' - ' remove_waters=False' - ' stop_if_r_free_greater_than=0.4' - ' update_waters=False' - + rfree + - ' build_hydrogens=False\n' - '\n' - 'fft hklin pipeline_1/refine_final.mtz mapout 2fofc.map << EOF\n' - ' labin F1=2FOFCWT_filled PHI=PH2FOFCWT\n' - 'EOF\n' - '\n' - 'fft hklin pipeline_1/refine_final.mtz mapout fofc.map << EOF\n' - ' labin F1=FOFCWT PHI=PHFOFCWT\n' - 'EOF\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal) + - '\n' - '/bin/rm phenix.ligand_pipeline.pdb\n' - '/bin/rm phenix.ligand_pipeline.mtz\n' - '\n' - 'ln -s phenix.ligand_pipeline/pipeline_1/refine_final.pdb phenix.ligand_pipeline.pdb\n' - 'ln -s phenix.ligand_pipeline/pipeline_1/refine_final.mtz phenix.ligand_pipeline.mtz\n' - '\n' - '/bin/rm init.pdb\n' - '/bin/rm init.mtz\n' - '\n' - 'ln -s phenix.ligand_pipeline.pdb init.pdb\n' - 'ln -s phenix.ligand_pipeline.mtz init.mtz\n' - '\n' - '/bin/rm 2fofc.map\n' - '/bin/rm fofc.map\n' - '\n' - 'ln -s phenix.ligand_pipeline/2fofc.map .\n' - 'ln -s phenix.ligand_pipeline/fofc.map .\n' - '\n' - '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_for_new_dimple_pdb.py')+ - ' {0!s} {1!s} {2!s}\n'.format(os.path.join(self.database_directory,self.data_source_file), xtal, self.initial_model_directory)+ - '\n' - '/bin/rm phenix.ligand_pipeline_run_in_progress\n' - ) - - os.chdir(self.ccp4_scratch_directory) - f = open('xce_{0!s}_{1!s}.sh'.format(self.pipeline, str(self.n)),'w') - f.write(Cmds) - f.close() - os.system('chmod +x xce_{0!s}_{1!s}.sh'.format(self.pipeline, str(self.n))) - self.n+=1 - db_dict= {'DimpleStatus': 'started'} - self.Logfile.insert('{0!s}: setting DataProcessingStatus flag to started'.format(xtal)) - self.db.update_data_source(xtal,db_dict) - - - def prepare_pipedream_shell_script(self,xtal,visit_run_autoproc,mtzin,ref_pdb,ref_mtz,ref_cif): - - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): - os.mkdir(os.path.join(self.initial_model_directory,xtal)) - if os.path.isdir(os.path.join(self.initial_model_directory,xtal,'pipedream')): - os.chdir(os.path.join(self.initial_model_directory,xtal)) - os.system('/bin/rm -fr pipedream') - os.mkdir(os.path.join(self.initial_model_directory,xtal,'pipedream')) - os.system('touch pipedream_run_in_progress') - - if self.queueing_system_available: - top_line='#PBS -joe -N XCE_{0!s}\n'.format(self.pipeline) - else: - top_line='#!'+os.getenv('SHELL')+'\n' - - if 'csh' in os.getenv('SHELL'): - ccp4_scratch='setenv CCP4_SCR '+self.ccp4_scratch_directory+'\n' - elif 'bash' in os.getenv('SHELL'): - ccp4_scratch='export CCP4_SCR='+self.ccp4_scratch_directory+'\n' - else: - ccp4_scratch='' - - if os.path.isdir('/dls'): - ccp4_scratch+='module load buster\n' - ccp4_scratch+='module load ccp4\n' - - if os.path.isfile(ref_mtz): - hklref_line=' -hklref {0!s}'.format(ref_mtz) - else: - hklref_line=' -nofreeref' - - Cmds = ( - '{0!s}\n'.format(top_line)+ - '\n' - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal,'pipedream') + - '\n' - 'source $XChemExplorer_DIR/setup-scripts/xce.setup-sh\n' - '\n' - +ccp4_scratch+ - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py %s %s %s %s\n' %(os.path.join(self.database_directory,self.data_source_file),xtal,'DimpleStatus','running') + - '\n' - 'pointless hklin {0!s} xyzin {1!s} hklout pointless.mtz > pointless.log\n'.format(mtzin,ref_pdb)+ - '\n' - 'pipedream ' - ' -d pipedreamDir' - ' -xyzin %s' %ref_pdb+ - hklref_line+ - ' -hklin pointless.mtz' - ' -keepwater\n' - '\n' - 'fft hklin pipedreamDir/refine/refine.mtz mapout 2fofc.map << EOF\n' - ' labin F1=2FOFCWT PHI=PH2FOFCWT\n' - 'EOF\n' - '\n' - 'fft hklin pipedreamDir/refine/refine.mtz mapout fofc.map << EOF\n' - ' labin F1=FOFCWT PHI=PHFOFCWT\n' - 'EOF\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal) + - '\n' - '/bin/rm pipedream.pdb\n' - '/bin/rm pipedream.mtz\n' - '\n' - 'ln -s pipedream/pipedreamDir/refine/refine.pdb pipedream.pdb\n' - 'ln -s pipedream/pipedreamDir/refine/refine.mtz pipedream.mtz\n' - '\n' - '/bin/rm init.pdb\n' - '/bin/rm init.mtz\n' - '\n' - 'ln -s pipedream.pdb init.pdb\n' - 'ln -s pipedream.mtz init.mtz\n' - '\n' - '/bin/rm 2fofc.map\n' - '/bin/rm fofc.map\n' - '\n' - 'ln -s pipedream/2fofc.map .\n' - 'ln -s pipedream/fofc.map .\n' - '\n' - '$CCP4/libexec/python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_for_new_dimple_pdb.py')+ - ' {0!s} {1!s} {2!s}\n'.format(os.path.join(self.database_directory,self.data_source_file), xtal, self.initial_model_directory)+ - '\n' - '/bin/rm pipedream_run_in_progress\n' - ) - - os.chdir(self.ccp4_scratch_directory) - f = open('xce_{0!s}_{1!s}.sh'.format(self.pipeline, str(self.n)),'w') - f.write(Cmds) - f.close() - os.system('chmod +x xce_{0!s}_{1!s}.sh'.format(self.pipeline, str(self.n))) - self.n+=1 - db_dict= {'DimpleStatus': 'started'} - self.Logfile.insert('{0!s}: setting DataProcessingStatus flag to started'.format(xtal)) - self.db.update_data_source(xtal,db_dict) - - - - -#pipedream -d pipedreamDir -xyzin $reference.pdb -hklref $referenceDataset.mtz -hklin $mtzFileUnique.mtz -rhofit $inhib.cif -target $reference.pdb -keepwater -nthreads 12 -postquick -allclusters |tee -a pipedream.log - - - def prepare_dimple_shell_script(self,xtal,visit_run_autoproc,mtzin,ref_pdb,ref_mtz,ref_cif): - - # check if reference mtzfile has an Rfree column; if not, then ignore - # DIMPLE assumes an Rfree column and barfs if it is not present - # note: ref_mtz looks like this: ref mtz -R reference.mtz - if os.path.isfile(ref_mtz): - mtz_column_dict=mtztools(ref_mtz).get_all_columns_as_dict() - if 'FreeR_flag' not in mtz_column_dict['RFREE']: - self.Logfile.insert('cannot find FreeR_flag in reference mtz file: {0!s} -> ignoring reference mtzfile!!!'.format(ref_mtz)) - ref_mtz = '' - if mtz_column_dict['RFREE']: - self.Logfile.insert('found Rfree set with other column name though: {0!s}'.format(str(mtz_column_dict['RFREE']))) - self.Logfile.insert('try renaming Rfree column to FreeR_flag with CAD!') - - db_dict= {'DimpleReferencePDB': ref_pdb} - self.db.update_data_source(xtal,db_dict) - - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'creating input script for '+xtal+' in '+visit_run_autoproc) - - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): - os.mkdir(os.path.join(self.initial_model_directory,xtal)) - os.chdir(os.path.join(self.initial_model_directory,xtal)) - if os.path.isdir(os.path.join(self.initial_model_directory,xtal,'dimple')): - os.system('/bin/rm -fr dimple') - os.mkdir(os.path.join(self.initial_model_directory,xtal,'dimple')) - os.system('touch dimple_run_in_progress') - os.system('/bin/rm final.mtz 2> /dev/null') - os.system('/bin/rm final.pdb 2> /dev/null') - - if self.queueing_system_available: - top_line='#PBS -joe -N XCE_dimple\n' - else: - top_line='#!'+os.getenv('SHELL')+'\n' - - if 'csh' in os.getenv('SHELL'): - ccp4_scratch='setenv CCP4_SCR '+self.ccp4_scratch_directory+'\n' - elif 'bash' in os.getenv('SHELL'): - ccp4_scratch='export CCP4_SCR='+self.ccp4_scratch_directory+'\n' - else: - ccp4_scratch='' - - if os.path.isdir('/dls'): - ccp4_scratch+='module load ccp4\n' - - hkl = any_reflection_file(file_name=mtzin) - miller_arrays = hkl.as_miller_arrays() - mtzFile = miller_arrays[0] - - if mtzFile.space_group_info().symbol_and_number() == 'R 3 :H (No. 146)': - symNoAbsence = 'H3' - else: - symNoAbsence = str([x[0] for x in str(mtzFile.space_group_info().symbol_and_number().split('(')[0]).split()]).replace('[','').replace(']','').replace("'","").replace(',','').replace(' ','') - - twin = '' - if self.dimple_twin_mode: - twin = "--refmac-key 'TWIN'" - - Cmds = ( - '{0!s}\n'.format(top_line)+ - '\n' - 'export XChemExplorer_DIR="'+os.getenv('XChemExplorer_DIR')+'"\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal,'dimple') + - '\n' - 'source $XChemExplorer_DIR/setup-scripts/xce.setup-sh\n' - '\n' - +ccp4_scratch+ - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py %s %s %s %s\n' %(os.path.join(self.database_directory,self.data_source_file),xtal,'DimpleStatus','running') + - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal,'dimple') + - '\n' - 'unique hklout unique.mtz << eof\n' - ' cell %s\n' %str([round(float(i),2) for i in mtzFile.unit_cell().parameters()]).replace('[','').replace(']','')+ - ' symmetry %s\n' %symNoAbsence+ - ' resolution %s\n' %str(round(float(mtzFile.d_min()),3))+ - 'eof\n' - '\n' -# 'freerflag hklin unique.mtz hklout free.mtz > freerflag.log\n' - '\n' - 'sftools << eof > sftools.log\n' - ' read unique.mtz\n' - ' calc col F = 10.0\n' - ' calc col SIGF = 1.0\n' - ' write sftools.mtz\n' - 'eof\n' - '\n' - 'cad hklin1 sftools.mtz hklin2 %s hklout %s.999A.mtz << eof\n' %(mtzin,xtal) + - ' monitor BRIEF\n' - ' labin file 1 E1=F E2=SIGF\n' - ' labout file 1 E1=F_unique E2=SIGF_unique\n' - ' labin file 2 ALL\n' - ' resolution file 1 999.0 %s\n' %str(round(float(mtzFile.d_min()),2))+ - 'eof\n' - '\n' - "dimple --no-cleanup %s.999A.mtz %s %s %s %s dimple\n" % (xtal, ref_pdb, ref_mtz, ref_cif, twin) + - '\n' - 'fft hklin dimple/final.mtz mapout 2fofc.map << EOF\n' - ' labin F1=FWT PHI=PHWT\n' - 'EOF\n' - '\n' - 'fft hklin dimple/final.mtz mapout fofc.map << EOF\n' - ' labin F1=DELFWT PHI=PHDELWT\n' - 'EOF\n' - '\n' - 'cd %s\n' %os.path.join(self.initial_model_directory,xtal) + - '\n' - '/bin/rm dimple.pdb\n' - '/bin/rm dimple.mtz\n' - '\n' - 'ln -s dimple/dimple/final.pdb dimple.pdb\n' - 'ln -s dimple/dimple/final.mtz dimple.mtz\n' - '\n' - '/bin/rm init.pdb\n' - '/bin/rm init.mtz\n' - '\n' - 'ln -s dimple.pdb init.pdb\n' - 'ln -s dimple.mtz init.mtz\n' - '\n' - '/bin/rm 2fofc.map\n' - '/bin/rm fofc.map\n' - '\n' - 'ln -s dimple/2fofc.map .\n' - 'ln -s dimple/fofc.map .\n' - '\n' - '$CCP4/bin/ccp4-python '+os.path.join(os.getenv('XChemExplorer_DIR'),'helpers','update_data_source_for_new_dimple_pdb.py')+ - ' {0!s} {1!s} {2!s}\n'.format(os.path.join(self.database_directory,self.data_source_file), xtal, self.initial_model_directory) + - '\n' - '/bin/rm dimple_run_in_progress\n' - '\n' - ) - - os.chdir(self.ccp4_scratch_directory) - f = open('xce_{0!s}_{1!s}.sh'.format(self.pipeline, str(self.n)),'w') - f.write(Cmds) - f.close() - os.system('chmod +x xce_{0!s}_{1!s}.sh'.format(self.pipeline, str(self.n))) - self.n+=1 - db_dict= {'DimpleStatus': 'started'} - self.Logfile.insert('{0!s}: setting DataProcessingStatus flag to started'.format(xtal)) - self.db.update_data_source(xtal,db_dict) - - - def run_script(self): - # submit job - self.Logfile.insert('created input scripts for '+str(self.n)+' in '+self.ccp4_scratch_directory) - os.chdir(self.ccp4_scratch_directory) - if os.path.isdir('/dls'): - if self.external_software['qsub_array']: - Cmds = ( - '#PBS -joe -N xce_{0!s}_master\n'.format(self.pipeline)+ - './xce_{0!s}_$SGE_TASK_ID.sh\n'.format(self.pipeline) - ) - f = open('{0!s}_master.sh'.format(self.pipeline),'w') - f.write(Cmds) - f.close() - self.Logfile.insert('submitting array job with maximal 100 jobs running on cluster') - self.Logfile.insert('using the following command:') - self.Logfile.insert('qsub -P labxchem -q medium.q -t 1:{0!s} -tc {1!s} {2!s}_master.sh'.format(str(self.n), self.max_queue_jobs, self.pipeline)) - os.system('qsub -P labxchem -q medium.q -t 1:{0!s} -tc {1!s} {2!s}_master.sh'.format(str(self.n-1), self.max_queue_jobs, self.pipeline)) - else: - self.Logfile.insert("cannot start ARRAY job: make sure that 'module load global/cluster' is in your .bashrc or .cshrc file") - elif self.external_software['qsub']: - self.Logfile.insert('submitting {0!s} individual jobs to cluster'.format((str(self.n)))) - self.Logfile.insert('WARNING: this could potentially lead to a crash...') - for i in range(1,self.n): - self.Logfile.insert('qsub -q medium.q xce_{0!s}_{1!s}.sh'.format(self.pipeline,str(i))) - os.system('qsub -q medium.q xce_{0!s}_{1!s}.sh'.format(self.pipeline,str(i))) - else: - self.Logfile.insert('running {0!s} consecutive {1!s} jobs on your local machine'.format(str(self.n-1),self.pipeline)) - for i in range(1,self.n): - self.Logfile.insert('starting xce_{0!s}_{1!s}.sh'.format(self.pipeline,str(i))) - os.system('./xce_{0!s}_{1!s}.sh'.format(self.pipeline,str(i))) - - - -class remove_selected_dimple_files(QtCore.QThread): - def __init__(self,sample_list,initial_model_directory,xce_logfile,database_directory,data_source_file,pipeline): - QtCore.QThread.__init__(self) - self.sample_list=sample_list - self.initial_model_directory=initial_model_directory - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(os.path.join(database_directory,data_source_file)) - self.pipeline = pipeline - - def run(self): - progress_step=1 - if len(self.sample_list) != 0: - progress_step=100/float(len(self.sample_list)) - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - for n,xtal in enumerate(self.sample_list): - db_dict={} - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): - self.Logfile.insert('{0!s}: directory does not exist'.format(xtal)) - continue - os.chdir(os.path.join(self.initial_model_directory,xtal)) - - if self.pipeline=='dimple': - if os.path.isfile('init.pdb'): - if 'dimple' in os.path.realpath('init.pdb'): - self.Logfile.warning('{0!s}: init.pdb & init.mtz is linked to dimple outcome'.format(xtal)) - self.Logfile.warning('{0!s}: removing init.pdb & init.mtz & (2)fofc maps'.format(xtal)) - db_dict = self.remove_init(db_dict) - else: - db_dict = self.remove_init(db_dict) - self.Logfile.warning('{0!s}: removing dimple folder & dimple.pdb/dimple.mtz'.format(xtal)) - os.system('/bin/rm dimple_run_in_progress 2> /dev/null') - os.system('/bin/rm dimple.pdb 2> /dev/null') - os.system('/bin/rm dimple.mtz 2> /dev/null') - os.system('/bin/rm -fr dimple') - elif self.pipeline=='pipedream': - if os.path.isfile('init.pdb'): - if 'dimple' in os.path.realpath('init.pdb'): - self.Logfile.warning('{0!s}: init.pdb & init.mtz is linked to pipedream outcome'.format(xtal)) - self.Logfile.warning('{0!s}: removing init.pdb & init.mtz & (2)fofc maps'.format(xtal)) - db_dict = self.remove_init(db_dict) - else: - db_dict = self.remove_init(db_dict) - self.Logfile.warning('{0!s}: removing pipedream folder & pipedream.pdb/pipedream.mtz'.format(xtal)) - os.system('/bin/rm pipedream_run_in_progress 2> /dev/null') - os.system('/bin/rm pipedream.pdb 2> /dev/null') - os.system('/bin/rm pipedream.mtz 2> /dev/null') - os.system('/bin/rm -fr pipedream') - elif self.pipeline=='phenix.ligand_pipeline': - if os.path.isfile('init.pdb'): - if 'dimple' in os.path.realpath('init.pdb'): - self.Logfile.warning('{0!s}: init.pdb & init.mtz is linked to phenix.ligand_pipeline outcome'.format(xtal)) - self.Logfile.warning('{0!s}: removing init.pdb & init.mtz & (2)fofc maps'.format(xtal)) - db_dict = self.remove_init(db_dict) - else: - db_dict = self.remove_init(db_dict) - self.Logfile.warning('{0!s}: removing phenix.ligand_pipeline folder & phenix.ligand_pipeline.pdb/phenix.ligand_pipeline.mtz'.format(xtal)) - os.system('/bin/rm phenix.ligand_pipeline_run_in_progress 2> /dev/null') - os.system('/bin/rm phenix.ligand_pipeline.pdb 2> /dev/null') - os.system('/bin/rm phenix.ligand_pipeline.mtz 2> /dev/null') - os.system('/bin/rm -fr phenix.ligand_pipeline') - - if db_dict != {}: - self.Logfile.insert('{0!s}: updating database'.format(xtal)) - self.db.update_data_source(xtal,db_dict) - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL('datasource_menu_reload_samples')) - - def remove_init(self,db_dict): - os.system('/bin/rm init.pdb') - os.system('/bin/rm init.mtz') - os.system('/bin/rm 2fofc.map') - os.system('/bin/rm fofc.map') - db_dict['DimpleResolutionHigh']='' - db_dict['DimpleRcryst']='' - db_dict['DimpleRfree']='' - db_dict['DimplePathToPDB']='' - db_dict['DimplePathToMTZ']='' - db_dict['DimpleReferencePDB']='' - db_dict['DimplePANDDAwasRun']='False' - db_dict['DimplePANDDAhit']='False' - db_dict['DimplePANDDAreject']='False' - db_dict['DimplePANDDApath']='' - db_dict['DimpleStatus']='pending' - return db_dict - - -class set_results_from_selected_pipeline(QtCore.QThread): - def __init__(self,sample_list,initial_model_directory,xce_logfile,database_directory,data_source_file,pipeline): - QtCore.QThread.__init__(self) - self.sample_list=sample_list - self.initial_model_directory=initial_model_directory - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(os.path.join(database_directory,data_source_file)) - self.pipeline = pipeline - - def run(self): - progress_step=1 - if len(self.sample_list) != 0: - progress_step=100/float(len(self.sample_list)) - progress=0 - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - for n,xtal in enumerate(self.sample_list): - db_dict={} - if not os.path.isdir(os.path.join(self.initial_model_directory,xtal)): - self.Logfile.insert('{0!s}: directory does not exist'.format(xtal)) - continue - os.chdir(os.path.join(self.initial_model_directory,xtal)) - - if os.path.isfile('init.pdb'): - self.Logfile.warning('{0!s}: init.pdb & init.mtz exist'.format(xtal)) - self.Logfile.warning('{0!s}: removing init.pdb & init.mtz & (2)fofc maps'.format(xtal)) - os.system('/bin/rm init.pdb') - os.system('/bin/rm init.mtz') - os.system('/bin/rm 2fofc.map') - os.system('/bin/rm fofc.map') - db_dict['DimpleResolutionHigh']='' - db_dict['DimpleRcryst']='' - db_dict['DimpleRfree']='' - db_dict['DimplePathToPDB']='' - db_dict['DimplePathToMTZ']='' - db_dict['DimpleReferencePDB']='' - db_dict['DimplePANDDAwasRun']='False' - db_dict['DimplePANDDAhit']='False' - db_dict['DimplePANDDAreject']='False' - db_dict['DimplePANDDApath']='' - db_dict['DimpleStatus']='pending' - - if self.pipeline=='dimple': - if os.path.isfile('dimple.pdb'): - self.Logfile.insert('%s: selecting output from dimple' %xtal) - os.system('ln -s dimple.pdb init.pdb') - pdb_info=parse().PDBheader('dimple.pdb') - db_dict['DimpleRcryst']=pdb_info['Rcryst'] - db_dict['DimpleRfree']=pdb_info['Rfree'] - db_dict['DimpleResolutionHigh']=pdb_info['ResolutionHigh'] - db_dict['DimpleStatus']='finished' - db_dict['DimplePathToPDB']=os.path.realpath('dimple.pdb') - if os.path.isfile('dimple.mtz'): - os.system('ln -s dimple.mtz init.mtz') - db_dict['DimplePathToMTZ']=os.path.realpath('dimple.mtz') - if os.path.isfile('dimple/2fofc.map'): - os.system('ln -s dimple/2fofc.map .') - if os.path.isfile('dimple/fofc.map'): - os.system('ln -s dimple/fofc.map .') - elif self.pipeline=='pipedream': - if os.path.isfile('pipedream.pdb'): - self.Logfile.insert('%s: selecting output from pipedream' %xtal) - os.system('ln -s pipedream.pdb init.pdb') - pdb_info=parse().PDBheader('pipedream.pdb') - db_dict['DimpleRcryst']=pdb_info['Rcryst'] - db_dict['DimpleRfree']=pdb_info['Rfree'] - db_dict['DimpleResolutionHigh']=pdb_info['ResolutionHigh'] - db_dict['DimpleStatus']='finished' - db_dict['DimplePathToPDB']=os.path.realpath('pipedream.pdb') - if os.path.isfile('pipedream.mtz'): - os.system('ln -s pipedream.mtz init.mtz') - db_dict['DimplePathToMTZ']=os.path.realpath('pipedream.mtz') - if os.path.isfile('pipedream/2fofc.map'): - os.system('ln -s pipedream/2fofc.map .') - if os.path.isfile('pipedream/fofc.map'): - os.system('ln -s pipedream/fofc.map .') - elif self.pipeline=='phenix.ligand_pipeline': - if os.path.isfile('phenix.ligand_pipeline.pdb'): - self.Logfile.insert('%s: selecting output from phenix.ligand_pipeline' %xtal) - os.system('ln -s phenix.ligand_pipeline.pdb init.pdb') - pdb_info=parse().PDBheader('phenix.ligand_pipeline.pdb') - db_dict['DimpleRcryst']=pdb_info['Rcryst'] - db_dict['DimpleRfree']=pdb_info['Rfree'] - db_dict['DimpleResolutionHigh']=pdb_info['ResolutionHigh'] - db_dict['DimpleStatus']='finished' - db_dict['DimplePathToPDB']=os.path.realpath('phenix.ligand_pipeline.pdb') - if os.path.isfile('phenix.ligand_pipeline.mtz'): - os.system('ln -s phenix.ligand_pipeline.mtz init.mtz') - db_dict['DimplePathToMTZ']=os.path.realpath('phenix.ligand_pipeline.mtz') - if os.path.isfile('phenix.ligand_pipeline/2fofc.map'): - os.system('ln -s phenix.ligand_pipeline/2fofc.map .') - if os.path.isfile('phenix.ligand_pipeline/fofc.map'): - os.system('ln -s phenix.ligand_pipeline/fofc.map .') - - self.Logfile.insert('{0!s}: updating database'.format(xtal)) - self.db.update_data_source(xtal,db_dict) - - progress += progress_step - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.emit(QtCore.SIGNAL('datasource_menu_reload_samples')) - - - -class start_COOT(QtCore.QThread): - - def __init__(self,settings,interface): - QtCore.QThread.__init__(self) - self.settings=settings - if interface=='test': - self.pylib='XChemCoot.py' - elif interface=='new': - self.pylib='XChemCootNew.py' - elif interface=='panddaV1': - self.pylib='XChemCootOld.py' - elif interface=='reference': - self.pylib='XChemCootReference.py' - - def run(self): - cwd=os.getcwd() - # coot at Diamond always or sometimes at least open in home directory, so then it won't find the .pkl file - pickle.dump(self.settings,open(os.path.join(os.getenv('HOME'),'.xce_settings.pkl'),'wb')) - os.system('cd {0!s}\ncoot --no-guano --no-state-script --script {1!s}'.format(os.getenv('HOME'), os.path.join(os.getenv('XChemExplorer_DIR'),'lib',self.pylib))) - - - -class start_ICM(QtCore.QThread): - - def __init__(self,html_export_directory): - QtCore.QThread.__init__(self) - self.html_export_directory=html_export_directory - - def run(self): - cwd=os.getcwd() - if cwd.startswith('/dls'): -# if not os.path.isfile(os.path.join('/home',getpass.getuser(),'.flexlmrc')): -# os.system('touch '+os.path.join('/home',getpass.getuser(),'.flexlmrc')) -# f=open(os.path.join('/home',getpass.getuser(),'.flexlmrc'),'w') -# f.write('MOLSOFTD_LICENSE_FILE=@diamvicmpro.diamond.ac.uk') -# f.close() - os.system('nautilus {0!s} &'.format(self.html_export_directory)) - os.system('/dls/science/groups/i04-1/software/icm-3.8-5/icm64 -g') - -class start_pandda_inspect(QtCore.QThread): - - def __init__(self,settings,xce_logfile): - QtCore.QThread.__init__(self) -# self.settings=settings - self.panddas_directory=settings['panddas_directory'] - self.xce_logfile=xce_logfile - self.Logfile=XChemLog.updateLog(xce_logfile) - - def run(self): - if os.getenv('SHELL') == '/bin/tcsh' or os.getenv('SHELL') == '/bin/csh': - source_file=os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-csh') - elif os.getenv('SHELL') == '/bin/bash': - source_file=os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh') - else: - source_file='' - - Cmds = ( - '#!'+os.getenv('SHELL')+'\n' - 'unset PYTHONPATH\n' - 'source '+source_file+'\n' - 'cd '+self.panddas_directory+'\n' - 'pandda.inspect\n' - ) - - self.Logfile.insert('starting pandda.inspect with the following command:\n'+Cmds) - os.system(Cmds) - -# Cmds = ( -# 'source '+os.path.join(os.getenv('XChemExplorer_DIR'),'setup-scripts','pandda.setup-sh')+'\n' -# 'cd '+self.panddas_directory+'\n' -# 'pandda.inspect\n' -# ) -# -# self.Logfile.insert('starting pandda.inspect with the following command:\n/bin/bash\n'+Cmds) -# # need to do this because we're having all sorts of csh bash issues at SGC -# os.system('/bin/bash\n'+Cmds) - - - - - -class start_dials_image_viewer(QtCore.QThread): - - def __init__(self,diffraction_image): - QtCore.QThread.__init__(self) - self.diffraction_image=diffraction_image - - def run(self): - os.system('dials.image_viewer '+self.diffraction_image) - - - - -# -# --- new module from hell ------------------------------------------------------------------------------------------- -# - -class read_pinIDs_from_gda_logs(QtCore.QThread): - def __init__(self, - beamline, - visit, - database, - gdaLogInstructions, - xce_logfile): - QtCore.QThread.__init__(self) - self.beamline = beamline - self.visit = visit - - self.xce_logfile = xce_logfile - self.Logfile = XChemLog.updateLog(xce_logfile) - - self.db = XChemDB.data_source(database) - self.allSamples = self.db.collected_xtals_during_visit_for_scoring(visit) - - self.gdaLogInstructions = gdaLogInstructions - self.gda_log_start_line = gdaLogInstructions[0] - self.gzipped_logs_parsed = gdaLogInstructions[1] - - def run(self): - if self.gzipped_logs_parsed: - self.Logfile.insert("parsed gzipped gda logfiles before, won't do again...") - self.Logfile.insert("will start parsing of current gda logfile at line {0!s}".format(str(self.gda_log_start_line))) - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'checking GDA logiles for pinID details') - pinDict, self.gda_log_start_line = XChemMain.get_gda_barcodes(self.allSamples, - self.gzipped_logs_parsed, - self.gda_log_start_line, - self.beamline, - self.xce_logfile) - - self.update_database(pinDict) - - self.gdaLogInstructions = [self.gda_log_start_line,True] - self.Logfile.insert('====== finished checking GDA logfiles ======') - self.emit(QtCore.SIGNAL('update_gdaLog_parsing_instructions_and_score'), self.gdaLogInstructions) - self.emit(QtCore.SIGNAL("finished()")) - - def update_database(self,pinDict): - self.Logfile.insert('updating database with pinDIs from GDA logfiles') - for sample in pinDict: - dbDict = {} - dbDict['DataCollectionPinBarcode'] = pinDict[sample] -# self.db.update_data_source(sample,dbDict) - self.db.update_specified_table(sample,dbDict,'collectionTable') - - -class choose_autoprocessing_outcome(QtCore.QThread): - def __init__(self, - database, - visit, - reference_file_list, - preferences, - projectDir, - rescore, - xce_logfile, - agamemnon): - QtCore.QThread.__init__(self) - self.visit = visit - self.projectDir = projectDir - self.reference_file_list = reference_file_list - self.rescore = rescore - self.selection_mechanism = preferences['dataset_selection_mechanism'] - self.acceptable_unitcell_volume_difference = preferences['allowed_unitcell_difference_percent'] - self.acceptable_low_resolution_limit_for_data = preferences['acceptable_low_resolution_limit_for_data'] - self.acceptable_low_resolution_Rmerge = preferences['acceptable_low_resolution_Rmerge'] - self.agamemnon = agamemnon - self.xce_logfile = xce_logfile - self.Logfile = XChemLog.updateLog(xce_logfile) - - self.db = XChemDB.data_source(os.path.join(database)) - if self.agamemnon: - self.allSamples = [] - for v in self.visit: - x = self.db.collected_xtals_during_visit_for_scoring(v) - for e in x: - self.allSamples.append(e) - else: - self.allSamples = self.db.collected_xtals_during_visit_for_scoring(visit) -# print 'here', self.allSamples -# self.allSamples = self.db.collected_xtals_during_visit_for_scoring(visit,rescore) - - - def run(self): - for sample in sorted(self.allSamples): - if self.db.autoprocessing_result_user_assigned(sample) and not self.rescore: - self.Logfile.warning('{0!s}: user has manually selected auto-processing result; will NOT auto-select!'.format(sample)) - continue - elif self.rescore: - self.Logfile.warning('{0!s}: rescore selected -> might overwrite user selection!'.format(sample)) - else: - self.Logfile.insert('%s: selecting autoprocessing result' % sample) - dbList = self.db.all_autoprocessing_results_for_xtal_as_dict(sample) - self.Logfile.insert('%s: found %s different autoprocessing results' %(sample,str(len(dbList)))) - - # 1.) if posssible, only carry forward samples with similar UCvolume and same point group - dbList = self.selectResultsSimilarToReference(dbList) - - # 2.) if possible, only carry forward samples with low resolution Rmerge smaller than - # specified in perferences - dbList = self.selectResultsWithAcceptableLowResoRmerge(dbList) - - # 3.) Make selection based on speified selection mechanism - if self.selection_mechanism == 'IsigI*Comp*UniqueRefl': - dbDict = self.selectHighestScore(dbList) - elif self.selection_mechanism == 'highest_resolution': - dbDict = self.selectHighestResolution(dbList) - elif 'only' in self.selection_mechanism: - dbDict = self.selectSpecificPipelineOnly(dbList) - - # 4.) Set new symbolic links in project directory - XChemMain.linkAutoProcessingResult(sample,dbDict,self.projectDir,self.xce_logfile) - - # 5.) Determine DataProcessing Outcome - dbDict['DataCollectionOutcome'] = self.determine_processing_outcome(dbDict) - - # 6.) update database - dbDict['DataProcessingAutoAssigned'] = 'True' - self.updateDB(sample,dbDict) - - self.emit(QtCore.SIGNAL('populate_datasets_summary_table_NEW')) - self.emit(QtCore.SIGNAL("finished()")) - - def report_forward_carried_pipelines(self,dbListOut,dbList): - if not dbListOut: - dbListOut = dbList - self.Logfile.warning('none of the MTZ files fulfilled criteria; will carry forward all results:') - else: - self.Logfile.insert('will carry forward the MTZ files from the following auto-processing pipelines:') - self.Logfile.insert('{0:30} {1:10} {2:10} {3:10}'.format('pipeline','Rmerge(Low)','PG','Score')) - self.Logfile.insert('----------------------------------------------------------------------') - for resultDict in dbListOut: - self.Logfile.insert('{0:30} {1:10} {2:10} {3:10}'.format(resultDict['DataProcessingProgram'], - resultDict['DataProcessingRmergeLow'], - resultDict['DataProcessingPointGroup'], - resultDict['DataProcessingScore'])) - return dbListOut - - def selectResultsSimilarToReference(self,dbList): - self.Logfile.insert('checking if MTZ files are similar to supplied reference files') - dbListOut = [] - for resultDict in dbList: - try: - if isinstance(float(resultDict['DataProcessingUnitCellVolume']),float): - self.Logfile.insert('checking unit cell volume difference and point group:') - for reference_file in self.reference_file_list: - if not reference_file[4]==0: - unitcell_difference=round((math.fabs(reference_file[4]-float(resultDict['DataProcessingUnitCellVolume']))/reference_file[4])*100,1) - self.Logfile.insert(resultDict['DataProcessingProgram'] + ': ' + - str(unitcell_difference) + '% difference -> pg(ref): ' + - reference_file[5] + ' -> pg(mtz): ' + resultDict['DataProcessingPointGroup']) - if unitcell_difference < self.acceptable_unitcell_volume_difference and reference_file[5]==resultDict['DataProcessingPointGroup']: - self.Logfile.insert('=> passed -> mtz file has same point group as reference file and similar unit cell volume') - dbListOut.append(resultDict) - else: - self.Logfile.warning('mtz file has different point group/ unit cell volume as reference file') - except ValueError: - pass - dbListOut = self.report_forward_carried_pipelines(dbListOut,dbList) - return dbListOut - - - def selectResultsWithAcceptableLowResoRmerge(self,dbList): - self.Logfile.insert('checking if MTZ files have acceptable low resolution Rmerge values (currently set to %s)' %str(self.acceptable_low_resolution_Rmerge)) - dbListOut = [] - for resultDict in dbList: - try: - if float(resultDict['DataProcessingRmergeLow']) < self.acceptable_low_resolution_Rmerge: - self.Logfile.insert(resultDict['DataProcessingProgram'] + - ': Rmerge(low) of MTZ file is below threshold: ' + - str(resultDict['DataProcessingRmergeLow'])) - dbListOut.append(resultDict) - else: - self.Logfile.warning(resultDict['DataProcessingProgram'] + - ': Rmerge(low) of MTZ file is ABOVE threshold: ' + - str(resultDict['DataProcessingRmergeLow'])) - except ValueError: - pass - dbListOut = self.report_forward_carried_pipelines(dbListOut,dbList) - return dbListOut - - - def selectHighestScore(self,dbList): - tmp = [] - for resultDict in dbList: - try: - tmp.append(float(resultDict['DataProcessingScore'])) - except ValueError: - tmp.append(0.0) - highestScoreDict = dbList[tmp.index(max(tmp))] - return highestScoreDict - - def selectHighestResolution(self,dbList): - tmp = [] - for resultDict in dbList: - try: - tmp.append(float(resultDict['DataProcessingResolutionHigh'])) - except ValueError: - tmp.append(100.0) - highestResoDict = dbList[tmp.index(min(tmp))] - return highestResoDict - - def selectSpecificPipelineOnly(self,dbList): - tmp = [] - for resultDict in dbList: - if self.selection_mechanism == 'dials - only' and 'dials' in resultDict['DataProcessingProgram']: - tmp.append(resultDict) - if self.selection_mechanism == 'xia2 3d - only' and '3d-run' in resultDict['DataProcessingProgram']: - tmp.append(resultDict) - if self.selection_mechanism == 'xia2 3dii - only' and '3dii-run' in resultDict['DataProcessingProgram']: - tmp.append(resultDict) - if self.selection_mechanism == 'autoProc - only' and resultDict['DataProcessingProgram'] == 'autoPROC': - tmp.append(resultDict) - if self.selection_mechanism == 'autoProc_staraniso - only' and resultDict['DataProcessingProgram'] == 'aP_staraniso': - tmp.append(resultDict) - if not tmp: - tmp = dbList - pipelineDict = self.selectHighestScore(tmp) - return pipelineDict - - - def determine_processing_outcome(self,db_dict): - outcome = 'Failed - unknown' - try: - if float(db_dict['DataProcessingResolutionHigh']) < self.acceptable_low_resolution_limit_for_data: - outcome = 'success' - else: - outcome = 'Failed - low resolution' - except ValueError: - pass - return outcome - - - def updateDB(self,sample, dbDict): - self.Logfile.insert('{0!s}: updating database'.format(sample)) - self.db.update_insert_data_source(sample, dbDict) - - -class read_write_autoprocessing_results_from_to_disc(QtCore.QThread): - - """ - major changes: - - pkl file is obsolete - - results for every autoprocessing result is recorded in new DB table - - crystal centring images are copied into project directory - - beamline directory in project directory will not be used anymore - - users need to actively select the actual data collection visit as Data Collection Directory in the - settings tab (e.g. /dls/i04-1/data/2017/mx15433-50 - - results from fast_dp are not copied over and included in analysis - - - DB mainTable gets flag if user updated autoprocessing selection - - checking of reprocessed files needs to be explicit - - all dictionaries used to store information are retired - - at the moment one can only review/ rescore crystals collected during the selected visit - - parsing of pinIDs in gda logfiles is still missing - """ - def __init__(self, - processedDir, - database, - projectDir, - xce_logfile, - target, - agamemnon): - QtCore.QThread.__init__(self) -# self.target = target - self.processedDir = processedDir - self.visit,self.beamline = XChemMain.getVisitAndBeamline(self.processedDir) -# print 'visit' - self.projectDir = projectDir - self.Logfile = XChemLog.updateLog(xce_logfile) - self.target = target - self.agamemnon = agamemnon - if self.agamemnon: -# print 'procDir',self.processedDir -# if len(procDir.split('/')) >= 8: -# if procDir.split('/')[7] == 'agamemnon' -# quit() - self.visit = 'agamemnon' # this is for trouble-shooting only - - self.db = XChemDB.data_source(os.path.join(database)) - self.exisitingSamples = self.getExistingSamples() - - self.toParse = [ - [ os.path.join('xia2', '*'), - os.path.join('LogFiles', '*aimless.log'), - os.path.join('DataFiles', '*free.mtz')], - [ os.path.join('multi-xia2', '*'), - os.path.join('LogFiles', '*aimless.log'), - os.path.join('DataFiles', '*free.mtz')], - [ os.path.join('autoPROC', '*'), - '*aimless.log', - '*truncate-unique.mtz'], - [ os.path.join('autoPROC', '*'), - '*staraniso_alldata-unique.table1', - '*staraniso_alldata-unique.mtz'], - [ os.path.join('autoPROC'), - '*aimless.log', - '*truncate-unique.mtz'], - [ os.path.join('autoPROC'), - '*summary.tar.gz', # staraniso_alldata-unique.table1 only available in tar archive - '*staraniso_alldata-unique.mtz'], - [ os.path.join('*'), - os.path.join('LogFiles', '*aimless.log'), - os.path.join('DataFiles', '*free.mtz')] - ] - - def run(self): - if self.agamemnon: - self.parse_agamemnon_file_system() - else: - self.parse_file_system() - - def getExistingSamples(self): - existingSamples={} - self.Logfile.insert('reading existing samples from collectionTable') - allEntries = self.db.execute_statement('select CrystalName,DataCollectionVisit,DataCollectionRun,DataProcessingProgram from collectionTable where DataCollectionOutcome = "success"') - for item in allEntries: - if str(item[0]) not in existingSamples: - existingSamples[str(item[0])]=[] - self.Logfile.insert('%s: adding %s' %(str(item[0]),str(item[1]))) - existingSamples[str(item[0])].append(str(item[1])+ '-' + str(item[2])+str(item[3])) - return existingSamples - - def createSampleDir(self,xtal): - if not os.path.isdir(os.path.join(self.projectDir,xtal)): - os.mkdir(os.path.join(self.projectDir,xtal)) - - def createAutoprocessingDir(self,xtal,run,autoproc): - # create all the directories if necessary - if not os.path.isdir(os.path.join(self.projectDir,xtal,'autoprocessing')): - os.mkdir(os.path.join(self.projectDir,xtal,'autoprocessing')) - if not os.path.isdir( - os.path.join(self.projectDir,xtal,'autoprocessing', self.visit + '-' + run + autoproc)): - os.mkdir(os.path.join(self.projectDir,xtal,'autoprocessing', self.visit + '-' + run + autoproc)) - - def cleanUpDir(self,xtal,run,autoproc,mtzfile,logfile): - toKeep = ['staraniso_alldata-unique.mtz','staraniso_alldata-unique.table1', - 'staraniso_alldata.log',xtal+'.mtz',xtal+'.log'] - os.chdir(os.path.join(self.projectDir,xtal,'autoprocessing', self.visit + '-' + run + autoproc)) - for files in glob.glob('*'): - if files not in toKeep: - os.system('/bin/rm -f ' + files) - - - def copyMTZandLOGfiles(self,xtal,run,autoproc,mtzfile,logfile): - mtzNew = '' - logNew = '' - os.chdir(os.path.join(self.projectDir,xtal,'autoprocessing', self.visit + '-' + run + autoproc)) - # MTZ file - if not os.path.isfile(mtzfile[mtzfile.rfind('/') + 1:]): - self.Logfile.insert('%s: copying %s' % (xtal, mtzfile)) - os.system('/bin/cp ' + mtzfile + ' .') - if os.path.isfile(mtzfile[mtzfile.rfind('/')+1:]) and not os.path.isfile(xtal+'.mtz'): - os.symlink(mtzfile[mtzfile.rfind('/')+1:], xtal + '.mtz') - if os.path.isfile(mtzfile[mtzfile.rfind('/') + 1:]): - mtzNew=os.path.join(self.projectDir,xtal,'autoprocessing', self.visit + '-' + run + autoproc, mtzfile[mtzfile.rfind('/')+1:]) - # AIMLESS logfile - if not os.path.isfile(logfile[logfile.rfind('/')+1:]): - self.Logfile.insert('%s: copying %s' % (xtal, logfile)) - os.system('/bin/cp ' + logfile + ' .') - if logfile.endswith('summary.tar.gz'): - self.Logfile.insert('unpacking summary.tar.gz') - os.system('tar -xzvf summary.tar.gz') - logfile = logfile.replace('summary.tar.gz','staraniso_alldata-unique.table1') - self.cleanUpDir(xtal,run,autoproc,mtzfile,logfile) - if os.path.isfile(logfile[logfile.rfind('/')+1:]) and not os.path.isfile(xtal+'.log'): - os.symlink(logfile[logfile.rfind('/')+1:], xtal + '.log') - if os.path.isfile(logfile[logfile.rfind('/') + 1:]): - logNew=os.path.join(self.projectDir,xtal,'autoprocessing', self.visit + '-' + run + autoproc, logfile[logfile.rfind('/') + 1:]) - return mtzNew,logNew - - def makeJPGdir(self,xtal,run): - if not os.path.isdir(os.path.join(self.projectDir,xtal,'jpg')): - self.Logfile.insert('making jpg directory in '+xtal) - os.mkdir(os.path.join(self.projectDir,xtal,'jpg')) - if not os.path.isdir( - os.path.join(self.projectDir,xtal,'jpg', self.visit + '-' + run)): - os.mkdir(os.path.join(self.projectDir,xtal,'jpg', self.visit + '-' + run)) - - def copyJPGs(self,xtal,run,auto): -# for img in glob.glob(os.path.join(self.processedDir.replace('processed','jpegs'),xtal,run+'*t.png')): -# for img in glob.glob(os.path.join(self.processedDir.replace('processed', 'jpegs'), run + '*t.png')): - self.Logfile.insert('%s: trying to copy crystal snapshots...' %xtal) - found = False - if self.agamemnon: - proposal = self.visit.split('-')[0] - self.Logfile.insert('looking for images in '+os.path.join(self.processedDir.replace(proposal,self.visit),'jpegs',auto,self.target,xtal,run + '*.0.png')) - for img in glob.glob(os.path.join(self.processedDir.replace(proposal,self.visit),'jpegs',auto,self.target,xtal,run + '*.0.png')): - if not os.path.isfile(os.path.join(self.projectDir,xtal,'jpg', self.visit +'-'+ run,img[img.rfind('/')+1:])): - self.Logfile.insert('%s: copying %s' % (xtal, img)) - os.system('/bin/cp %s %s' %(img,os.path.join(self.projectDir,xtal,'jpg', self.visit + '-' + run))) - else: - for img in glob.glob(os.path.join(self.processedDir.replace('processed', 'jpegs'), run + '*.0.png')): - found = True - if not os.path.isfile(os.path.join(self.projectDir,xtal,'jpg', self.visit +'-'+ run,img[img.rfind('/')+1:])): - self.Logfile.insert('%s: copying %s' % (xtal, img)) - os.system('/bin/cp %s %s' %(img,os.path.join(self.projectDir,xtal,'jpg', self.visit + '-' + run))) - if not found: - for img in glob.glob(os.path.join(self.processedDir.replace('processed', 'jpegs'), xtal, run + '*.0.png')): - if not os.path.isfile(os.path.join(self.projectDir, xtal, 'jpg', self.visit + '-' + run, img[img.rfind('/') + 1:])): - self.Logfile.insert('%s: copying %s' % (xtal, img)) - os.system('/bin/cp %s %s' % (img, os.path.join(self.projectDir, xtal, 'jpg', self.visit + '-' + run))) - - - - def findJPGs(self,xtal,run): - jpgDict={} -# for n,img in enumerate(glob.glob(os.path.join(self.projectDir,xtal,'jpg', self.visit +'-'+ run,'*t.png'))): - for n,img in enumerate(glob.glob(os.path.join(self.projectDir,xtal,'jpg', self.visit +'-'+ run,'*.0.png'))): - if n <= 3: jpgDict['DataCollectionCrystalImage'+str(n+1)]=img - return jpgDict - - - def readProcessingUpdateResults(self,xtal,folder,log,mtz,timestamp,current_run,autoproc): - db_dict = {} - for mtzfile in glob.glob(os.path.join(folder,mtz)): - for logfile in glob.glob(os.path.join(folder, log)): - self.createAutoprocessingDir(xtal, current_run, autoproc) - mtzNew,logNew = self.copyMTZandLOGfiles(xtal,current_run,autoproc,mtzfile,logfile) - if self.target == '=== project directory ===': - target = 'unknown' - else: - target = self.target - db_dict = { 'DataCollectionDate': timestamp, - 'DataProcessingPathToLogfile': logNew, - 'DataProcessingPathToMTZfile': mtzNew, - 'DataProcessingDirectoryOriginal': folder, - 'DataCollectionOutcome': 'success', # success in collection Table only means that a logfile was found - 'ProteinName': target } - db_dict.update(parse().read_aimless_logfile(logNew)) - db_dict.update(self.findJPGs(xtal,current_run)) # image exist even if data processing failed - db_dict['DataCollectionBeamline'] = self.beamline - self.update_data_collection_table(xtal,current_run,autoproc,db_dict) -# return db_dict - - def getAutoProc(self,folder): - autoproc='unkown' - if 'ap-run' in folder: - autoproc = 'autoPROC' - else: - autoproc = folder.split('/')[len(folder.split('/'))-1] - return autoproc - - def update_data_collection_table(self,xtal,current_run,autoproc,db_dict): - condition_dict = { 'CrystalName': xtal, - 'DataCollectionVisit': self.visit, - 'DataCollectionRun': current_run, - 'DataProcessingProgram': autoproc } - self.db.update_insert_any_table('collectionTable', db_dict, condition_dict) - - def alreadyParsed(self,xtal,current_run,autoproc): - parsed=False - if xtal in self.exisitingSamples: - if self.visit + '-' + current_run + autoproc in self.exisitingSamples[xtal]: - self.Logfile.insert( - '%s: results from %s already parsed; skipping...' % ( - xtal, self.visit + '-' + current_run + autoproc)) - parsed=True - return parsed - - def empty_folder(self,xtal,folder): - empty = True - stuff = [] - for x in glob.glob(os.path.join(folder,'*')): - stuff.append(x) - if not stuff: - self.Logfile.warning( - '{0!s}: {1!s} is empty; probably waiting for autoprocessing to finish; try later!'.format(xtal, folder)) - else: - empty = False - return empty - - def junk(self,folder): - do_not_parse = False - if not os.path.isdir(folder): - do_not_parse = True - elif 'dimple' in folder: - do_not_parse = True - return do_not_parse - - def parse_file_system(self): - self.Logfile.insert('checking for new data processing results in '+self.processedDir) - progress = 0 - progress_step = XChemMain.getProgressSteps(len(glob.glob(os.path.join(self.processedDir,'*')))) - - runList = [] - for collected_xtals in sorted(glob.glob(os.path.join(self.processedDir,'*'))): - # why is this here? self.visit is derived in init function through XChemMain.getVisitAndBeamline -# self.visit = collected_xtals.split('/')[5] - if 'tmp' in collected_xtals or 'results' in collected_xtals or 'scre' in collected_xtals: - continue - if not os.path.isdir(collected_xtals): - self.Logfile.warning(collected_xtals + ' is not a directory') - continue - - xtal = collected_xtals[collected_xtals.rfind('/')+1:] - if self.agamemnon: - tmp = xtal[:xtal.rfind('_')] - xtal = tmp[:tmp.rfind('_')] - - self.Logfile.insert('%s: checking auto-processing results' %xtal) - self.createSampleDir(xtal) - - if self.target == '=== project directory ===': - runDir = os.path.join(collected_xtals,'processed','*') - elif self.agamemnon: - tmpDir = collected_xtals[:collected_xtals.rfind('/')] - runDir = os.path.join(tmpDir,xtal+'_*_') - else: - runDir = os.path.join(collected_xtals,'*') - - for run in sorted(glob.glob(runDir)): - current_run=run[run.rfind('/')+1:] - if current_run in runList: - continue - self.Logfile.insert('%s -> run: %s -> current run: %s' %(xtal,run,current_run)) - timestamp=datetime.fromtimestamp(os.path.getmtime(run)).strftime('%Y-%m-%d %H:%M:%S') - - # create directory for crystal aligment images in projectDir - self.makeJPGdir(xtal,current_run) - self.copyJPGs(xtal, current_run, 'non-auto') # 'non-auto' is irrelevant here - - for item in self.toParse: - procDir = os.path.join(run,item[0]) - logfile = item[1] - mtzfile = item[2] - - for folder in glob.glob(procDir): - if self.junk(folder): - continue - if self.empty_folder(xtal,folder): - continue - if 'staraniso' in logfile or 'summary.tar.gz' in logfile: - autoproc = 'aP_staraniso' - else: - autoproc = self.getAutoProc(folder) - if self.alreadyParsed(xtal,current_run,autoproc): - continue - self.readProcessingUpdateResults(xtal,folder,logfile,mtzfile,timestamp,current_run,autoproc) - runList.append(current_run) - - progress += progress_step - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'parsing auto-processing results for '+xtal) - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.Logfile.insert('====== finished parsing beamline directory ======') - self.emit(QtCore.SIGNAL('read_pinIDs_from_gda_logs')) - self.emit(QtCore.SIGNAL("finished()")) - - def parse_agamemnon_file_system(self): - self.Logfile.insert('checking for new data processing results in '+self.processedDir) - progress = 0 - progress_step = 1 - - autoDir = ['auto','agamemnon'] - - c = 0 - for auto in autoDir: - for collected_xtals in sorted(glob.glob(os.path.join(self.processedDir+'-*','processed',auto,self.target,'*'))): - if 'tmp' in collected_xtals or 'results' in collected_xtals or 'scre' in collected_xtals: - continue - c += 1 - - if c > 0: - progress_step = 100/float(c) - self.Logfile.insert('found %s samples of target %s' %(str(c),self.target)) - else: - self.Logfile.warning('found %s samples of target %s' %(str(c),self.target)) - - runList = [] - - autoDir = ['auto','agamemnon'] - - for auto in autoDir: - for collected_xtals in sorted(glob.glob(os.path.join(self.processedDir+'-*','processed',auto,self.target,'*'))): - self.visit = collected_xtals.split('/')[5] - if 'tmp' in collected_xtals or 'results' in collected_xtals or 'scre' in collected_xtals: - continue - if not os.path.isdir(collected_xtals): - continue - - xtal = collected_xtals[collected_xtals.rfind('/')+1:] - if xtal.endswith('_'): - continue # happened sometime during testing, but should not happen anymore - - self.Logfile.insert('%s: checking auto-processing results' %xtal) - self.createSampleDir(xtal) - - for run in sorted(glob.glob(os.path.join(collected_xtals,'*'))): - current_run=run[run.rfind('/')+1:] - if current_run not in runList: - runList.append(current_run) - else: - continue - self.Logfile.insert('%s -> run: %s -> current run: %s' %(xtal,run,current_run)) - timestamp=datetime.fromtimestamp(os.path.getmtime(run)).strftime('%Y-%m-%d %H:%M:%S') - - # create directory for crystal aligment images in projectDir - self.makeJPGdir(xtal,current_run) - self.copyJPGs(xtal, current_run, auto) - - for item in self.toParse: - procDir = os.path.join(run,item[0]) - logfile = item[1] - mtzfile = item[2] - - for folder in glob.glob(procDir): - for mtz in glob.glob(os.path.join(procDir,mtzfile)): - print mtz - - for folder in glob.glob(procDir): - if self.junk(folder): - continue - if self.empty_folder(xtal,folder): - continue - if 'staraniso' in logfile or 'summary.tar.gz' in logfile: - autoproc = 'aP_staraniso' - else: - autoproc = self.getAutoProc(folder) - if self.alreadyParsed(xtal,current_run,autoproc): - continue - self.readProcessingUpdateResults(xtal,folder,logfile,mtzfile,timestamp,current_run,autoproc) - - - - - progress += progress_step - self.emit(QtCore.SIGNAL('update_status_bar(QString)'), 'parsing auto-processing results for '+collected_xtals) - self.emit(QtCore.SIGNAL('update_progress_bar'), progress) - - self.Logfile.insert('====== finished parsing beamline directory ======') - self.emit(QtCore.SIGNAL('read_pinIDs_from_gda_logs')) - self.emit(QtCore.SIGNAL("finished()")) - diff --git a/lib/XChemToolTips.py b/lib/XChemToolTips.py deleted file mode 100755 index a4aa2df5..00000000 --- a/lib/XChemToolTips.py +++ /dev/null @@ -1,428 +0,0 @@ -# last edited: 03/08/2017, 17:00 - -import os -import getpass - -def dataset_task_tip(): - tip = ( 'describes what you can do' ) - return tip - -def dataset_task_run_button_tip(): - tip = ( 'Run dataset' ) - return tip - -def dataset_task_status_button_tip(): - tip = ( 'Status dataset' ) - return tip - -def map_cif_file_task_tip(): - tip = ( 'describes what you can do' ) - return tip - -def map_cif_file_task_run_button_tip(): - tip = ( 'Run map_cif_file' ) - return tip - -def map_cif_file_task_status_button_tip(): - tip = ( 'Status map_cif_file' ) - return tip - -def panddas_file_task_tip(): - tip = ( 'describes what you can do' ) - return tip - -def panddas_file_task_run_button_tip(): - tip = ( 'Run panddas_file' ) - return tip - -def panddas_file_task_status_button_tip(): - tip = ( 'Status panddas_file' ) - return tip - -def refine_file_task_tip(): - tip = ( 'describes what you can do' ) - return tip - -def refine_file_task_run_button_tip(): - tip = ( 'Run refine_file' ) - return tip - -def refine_file_task_status_button_tip(): - tip = ( 'Status refine_file' ) - return tip - -def validation_file_task_tip(): - tip = ( 'describes what you can do' ) - return tip - -def validation_file_task_run_button_tip(): - tip = ( 'Run validation_file' ) - return tip - -def validation_file_task_status_button_tip(): - tip = ( 'Status validation_file' ) - return tip - -def update_from_datasource_button_tip(): - tip = ( 'Status validation_file' ) - return tip - - - - -def load_samples_from_datasource(): - tip = ( 'loads all information\n' - 'which is currently in the\n' - 'data source' ) - return tip - -def save_samples_to_datasource(): - tip = ( 'saves all changes you made\n' - 'to any of the cells to the\n' - 'data source' ) - return tip - -def create_pdb_cif_png_files(): - tip = ( 'uses ACEDRG to create pdb,cif and png files for all compounds\n' - 'that have a smiles string assigned. The compounds ID\n' - 'serves as name if available.\n' - 'The files are written to initial_model//compound\n' - 'data source' ) - return tip - -def check_status_create_pdb_cif_png_files(): - tip = ( 'the jobs are sent to a computer cluster if available\n' - 'gives you an overview about how it progresses') - return tip - -def run_pandda_inspect_at_home(pandda_directory): -# instruction = ( '\n\n' -# 'Please follow the instructions below to run pandda.inspect at your home institution:\n\n' -# ' 1. Make sure that the pandda package is installed at your home institution.\n' -# ' For more details see: http://pandda.bitbucket.org\n\n' -# ' 2. At home: go to the folder where you want the files from pandda.analyse to be;\n' -# ' e.g. cd /home/tkrojer/fragment_screening\n\n' -# ' 3. At home: run the following command:\n' -# ' rsync -av %s@nx.diamond.ac.uk:%s .\n\n' %(getpass.getuser(),pandda_directory)+ -# ' 4. At home: go into the pandda directory\n' -# ' cd %s\n\n' %pandda_directory[pandda_directory.rfind('/')+1:]+ -# ' 5. At home: run pandda.inspect\n' -# ' pandda.inspect\n\n' -# ' 6. Once you finished inspecting your models, close pandda.inspect and copy the data back to DLS\n' -# ' with the following command:\n' -# ' rsync -av * %s@nx.diamond.ac.uk:%s\n\n' %(getpass.getuser(),pandda_directory)+ -# ' 7. At DLS: continue using XChemExplorer; go to the PANDDA tab and run:\n' -# ' "Export PANDDA models"\n' -# ' This will trigger the following steps:\n' -# ' - transform the pandda models back into the crystallographic unit cell\n' -# ' - copy the transformed models into the respective folder of the project directory\n' -# ' - launch an initial round of refinement with REFMAC\n' -# ' Note: All refinement jobs run on the cluster at DLS.\n' -# ' You can check the status of the jobs by typing:\n' -# ' module load global/cluster\n' -# ' qstat\n\n' -# ' 8. At DLS: go to the REFINEMENT tab and run "Open COOT" to review and further refine your models if necessary\n' ) - - instruction = ( '\n\n' - 'Be sure to have pandda installed at home, and go to a clean subdirectory.\n' - 'From that directory, do the steps below.\n' - 'This moves the relevant files to your site so you can do the model building locally, and then moves the files back to Diamond.\n' - '1. run: rsync -av %s@nx.diamond.ac.uk:%s .\n' %(getpass.getuser(),pandda_directory)+ - '2. run: "pandda.inspect", and build all relevant models, etc.\n' - '3. run: rsync -av * %s@nx.diamond.ac.uk:%s\n' %(getpass.getuser(),pandda_directory)+ - 'Now proceed within XChemExplorer as before.\n' ) - - print instruction - -def deposition_interface_note(): - - note = ( '\n\n' - 'Note: you can use this mask to save identical information for ALL structures to be deposited.\n' - 'However, this may not be suitable in cases where the information is different for certain samples.\n' - 'In such cases, please use for example SQLiteBrowser to edit the relevant fields in the depositTable.' ) - - return note - -def html_summary_introduction(): - - text = ( 'This section describes how to generate an HTML summary page of the current project. \n' - 'All you need to do is select the HTML output directory where the html and additional auxiliary files \n' - 'and will be written to. ' - 'Then press the "Export to HTML" button and \nall bound structures that are labeled as "4 - compchem ready"' - 'or higher will be included in the final document. \n' - 'Please checkout https://www.thesgc.org/fragment-screening to see what the final pages look like. ') - - return text - -def html_export_directory_background(): - - text = ( 'The HTML export directory will contain all files necessary to generate the summary file.\n' - 'It is also makes it easy to share the results with collaborators.') - - return text - -def html_export_step(): - - text = ( 'This step will create an index.html file and it will copy pdb, mtz and cif files\n' - 'as well as PanDDA event maps into the html export directory.' ) - - return text - - -def icb_file_background(): - - text = ( 'This step will use ICM-pro to create interactive structure thumbnails in the html file (http://www.molsoft.com/activeicmjs.html)') - - return text - - - -def prepare_ICB_files(): - - instruction = ( '- Open file browser and navigate to HTML export directory.\n' - '- Open ICM (at DLS: select SERVER and enter diamvicmpro.diamond.ac.uk in case ICM asks).\n' - '- Drag-and-drop dsEvent_sqlite.icm file into ICM main window.\n' - '- In ICM workspace panel: right-click on dsEvent_sqlite.icm and select "RUN".') - return instruction - -def zenodo_upload_start(html_export_directory): - - instruction = ( 'This will copy all files required for ZENODO upload to\n' - '%s' %os.path.join(html_export_directory,'zenodo') ) - return instruction - -def zenodo_upload_part_one(html_export_directory): - - instruction = ( '- Register with ZENODO (www.zenodo.org)\n' - '- Select Upload -> New Upload\n' - '- upload all files from %s/zenodo, BUT NOT any of the .html files!!!' %html_export_directory ) - return instruction - -def zenodo_upload_part_two(): - - instruction = ( 'You might have noticed that once you started uploading files, the address bar in your browser will change to something like this:') - - return instruction - -def zenodo_upload_part_three(): - - instruction = ( 'Please enter the upload ID, i.e. the number at the end of the line, into the field below') - - return instruction - -def zenodo_upload_part_four(html_export_directory): - - instruction = ( 'Upload ALL html files in {0!s} to ZENODO and publish the page.'.format(os.path.join(html_export_directory,'zenodo'))) - - return instruction - -def deposition_pandda_site_not_ready(xtal): - msg = ( 'Please make sure that all placed ligands in '+xtal+' are ready for deposition.\n' - 'Go to the Refinement tab -> Open COOT and either delete the ligand or set the site ' - ' to "5 - Deposition ready"' ) - return msg - -def pandda_pre_run(reference_directory): - msg = ( 'The aim of the pre-run is NOT to identify bound ligands,\n' - 'but to create mean ground state maps.\n' - 'Hence, the pre-run will only comprise 100 datasets.\n' - 'After the pre-run is finished use the resulting ground state mean maps\n' - 'to build a suitable reference model for the subsequent PanDDA production run.\n' - 'The appendix will determine the name of the folder where the results from\n' - 'the pre-run will be stored. It is used by the COOT plugin to distinguish\n' - 'between different pre-runs.\n' - 'The result from the pre-run will be stored in:\n' - '%s/pannda_'https://openlabnotebooks.org/update-on-batch-deposition-of-xchem-structures'
" - ) - return lnk - -def deposition_bound_state_prerequisites(): - msg = ( - '1. Event map to MTZ conversion.\n' - ' All pandda event maps need to be converted to MTZ format. This is currently not done automatically.\n' - ' If you have not done so, select and run "Event Map -> SF" from the Hit Identification action box.\n' - ' This may take a while, but you only need to run this once.\n' - '2. Select datasets to be deposited.\n' - ' Set crystals to "5-ready for deposition" in XCE refinement tab\n' - '3. Enter additional data required for PDB deposition.\n' - ' In the Deposition menu, select "Edit information". Fill out all the required items and press "Save to Database".\n' - ' Note: this needs to be done after the datasets have been selected for deposition.' - ) - return msg - -def deposition_bound_state_preparation_step_one_text(): - msg = ( - '1. Press the button below to generate structure and structure factor mmcif files of all selected datasets.\n' - ' Note: all previously generated mmcif files will be overwritten.' - ) - return msg - -def deposition_bound_state_preparation_step_two_text(): - msg = ( - '2. Press the button below to copy all the mmcif files into the "group deposition directory" (see settings tab).\n' - 'All mmcif files will be bundled into a single, bzipped tar archive which can be uploaded into via the PDB group deposition website.' - ) - return msg - -def pdb_group_deposition_instruction_one(): - msg = ( - '3. Go to the group deposition website, create a session and upload the ligand-bound.tar.bz2 file from the group deposition directory.' - ) - return msg - -def pdb_group_deposition_link(): - lnk = ( - "'https://deposit-group-1.rcsb.rutgers.edu/groupdeposit'" - ) - return lnk - -def pdb_group_deposition_instruction_two(): - msg = ( - ' user: grouptester\n' - ' password: !2016rcsbpdb ' - ) - return msg - -def deposition_ground_state_prerequisites(): - msg = ( - '1. Convert all apo MTZ files to mmcif format.\n' - ' Swtich to the pandda tab, select the PanDDA directory which contains the analysis you want to deposit.\n' - ' Then select and run "apo -> mmcif" from the Hit Identification action box.\n' - ' Note: you only need to do this once.' - ) - return msg - - -def deposition_ground_state_preparation_step_one_text(): - msg = ( - '1. Select ground-state PDB file.\n' - ' Note: the file is usually in the reference directory.' - ) - return msg - -def deposition_ground_state_log_info(): - msg = ( - ' IMPORTANT:\n' - ' Make sure that a file or symlink to an AIMLESS logile with the same name root as your ground-state PDB file\n' - ' is present in the same folder. This is currently not generated automatically! ' - ) - return msg - -def deposition_ground_state_preparation_step_two_text(): - msg = ( - '2. Select ground-state MTZ file.\n' - ' Notes: - this is the MTZ file of the ground-state mean map\n' - ' - the file should have been created after the pandda pre-run\n' - ' - hence, you will usually find it in the reference directory' - ) - return msg - -def deposition_ground_state_preparation_step_three_text(): - msg = ( - '3. Please check the settings tab that you have selected the correct pandda directory.\n' - ' (Note: we will take all the apo mmcif files from this directory)\n' - ' Current PanDDA directory:' - ) - return msg - -def deposition_ground_state_preparation_step_four_text(): - msg = ( - '4. Add the ground-state entry to the database.' - ) - return msg - -def deposition_ground_state_preparation_step_five_text(): - msg = ( - '5. Enter meta-data for ground-state model:\n' - ' - Open "Deposition -> Edit information"\n' - ' - Fill out form or load .deposit file\n' - ' - Press "Save to Database"\n' - ' - Press "OK"' - ) - return msg - -def deposition_ground_state_preparation_step_six_text(): - msg = ( - '6. Prepare the ground-state mmcif file.\n' - ' Note: the mmcif files are saved into the selected pandda directory' - ) - return msg - -def deposition_ground_state_preparation_step_seven_text(): - msg = ( - '7. Press the button below to copy the structire and structure factor mmcif files into the "group deposition directory" (see settings tab).\n' - 'Both mmcif files will be bundled into a single, bzipped tar archive which can be uploaded into via the PDB group deposition website.' - ) - return msg - -def deposition_ground_state_preparation_step_eight_text(): - msg = ( - '8. Go to the group deposition website, create a session and upload the ligand-bound.tar.bz2 file from the group deposition directory.' - ) - return msg - -def after_deposition_step_one_text(): - msg = ( - 'After you have successfully submitted the ligand-bound structures via the PDB group deposition interface, you will immediately get\n' - 'an email with the PDB codes. There will be a single line for each PDB submission. Highlight and copy the text! Then go to the "Deposition" menu\n' - 'and select "Update DB with PDB codes". A pop-up window will appear, paste the text into the window and press "Update Database".' - ) - return msg - -def deposition_bounnd_state_preparation_ignore_event_map(): - msg = ( - 'do NOT include PanDDA event maps (ONLY USE IN CASE IF DATA WERE NOT ANALYSED WITH PANDDA!)' - ) - return msg - -def second_cif_file_info(cif_file): - second_cif_file = str(cif_file) - if os.path.isfile(second_cif_file): - msg = ( - 'You have selected the following restraints file\n' - 'for merging into the the ligand CIF files:\n' - +second_cif_file+ - '\n' - 'Press NO in case you do not want to continue\n' - 'In case you want to use another file, open the preferences menu and set it there\n' - 'Please check the XCE logfile in case of unexpected behaviour' - ) - elif second_cif_file.replace(' ','') == '' or second_cif_file.lower() == 'none': - msg = ( - 'No restraints file was selected!' - ) - else: - msg = ( - 'The selected restraints file does not exist:\n' - +second_cif_file+ - '\n' - 'Open the preferences menu and set it there\n' - ) - return msg - -def second_cif_file_not_exists(): - msg = ( - 'The CIF file for the non-standard ligand does not exist! ' - 'It was either not selected or the file was deleted/ moved in the meantime. ' - 'Please check Menu -> Preferences.' - ) - return msg \ No newline at end of file diff --git a/lib/XChemUtils.py b/lib/XChemUtils.py deleted file mode 100755 index 83c268cf..00000000 --- a/lib/XChemUtils.py +++ /dev/null @@ -1,2595 +0,0 @@ -# last edited: 07/07/2017, 17:00 - -import sys -import os -import glob -import math -import subprocess -import getpass -import shutil -import math -import platform -import tarfile - - -from rdkit import Chem -from rdkit.Chem import AllChem -from rdkit.Chem import Draw - -import iotbx.pdb - -from iotbx.reflection_file_reader import any_reflection_file -from iotbx import mtz - -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -import XChemDB -import XChemLog - - -class process: - - def __init__(self,dimple): - self.project_directory=dimple['project_directory'] - self.delete_old=dimple['delete_old'] - self.xtalID=dimple['xtalID'] - self.reference=dimple['reference'] - self.queueing_system_available=dimple['queueing_system_available'] - self.ccp4_scratch_directory=dimple['ccp4_scratch'] - self.fileroot_in=dimple['fileroot_in'] - self.mtz_free=self.fileroot_in+'.free.mtz' - self.mtz_in=self.fileroot_in+'.mtz' - # need to set $CCP4_SCR, because the default directory in /home/zqr16691/tmp fills up easily - # and then dimple will not run -# if not os.path.isdir(self.project_directory[:self.project_directory.find('processing')+11]+'/tmp'): -# os.mkdir(self.project_directory[:self.project_directory.find('processing')+11]+'/tmp') -# self.ccp4_scratch=self.project_directory[:self.project_directory.find('processing')+11]+'/tmp' - - - def get_Rfree(self): - Cmds='' - if not os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.mtz_free)): - if os.path.isfile(os.path.join(self.project_directory,self.xtalID,self.reference+'.mtz')): - Cmds = ( -# '#!'+os.getenv('SHELL')+'\n' - '\n' - 'cd %s/%s/Dimple\n' %(self.project_directory,self.xtalID) + - '\n' - 'pointless hklin ../%s hklref %s.mtz hklout %s.reind.mtz << EOF > pointless.log\n' %(self.mtz_in,self.reference,self.xtalID)+ - ' tolerance 5\n' - 'EOF\n' - '\n' - 'cad hklin1 %s.reind.mtz hklin2 %s.mtz hklout cad.mtz << EOF > cad.log\n' %(self.xtalID,self.reference) + - ' labin file_number 1 E1=F E2=SIGF E3=IMEAN E4=SIGIMEAN\n' - ' labout file_number 1 E1=F E2=SIGF E3=IMEAN E4=SIGIMEAN\n' - ' labin file_number 2 E1=FreeR_flag\n' - ' labout file_number 2 E1=FreeR_flag\n' - ' END\n' - 'EOF\n' - '\n' - 'freerflag hklin cad.mtz hklout ../%s << EOF > freerflag.log\n' %self.mtz_free + - ' COMPLETE FREE=FreeR_flag\n' - ' END\n' - 'EOF\n' - '#uniqueify -f FreeR_flag cad.mtz ../%s\n' %self.mtz_free - ) - else: - Cmds = ( -# '#!'+os.getenv('SHELL')+'\n' - '\n' - 'cd %s/%s/Dimple\n' %(self.project_directory,self.xtalID) + - '\n' - 'pointless hklin ../%s xyzin %s.pdb hklout %s.reind.mtz << EOF > pointless.log\n' %(self.mtz_in,self.reference,self.xtalID)+ - ' tolerance 5\n' - 'EOF\n' - '\n' - 'cad hklin1 %s.reind.mtz hklout cad.mtz << EOF > cad.log\n' %self.xtalID + - ' labin file_number 1 E1=F E2=SIGF E3=IMEAN E4=SIGIMEAN\n' - ' labout file_number 1 E1=F E2=SIGF E3=IMEAN E4=SIGIMEAN\n' - ' END\n' - 'EOF\n' - '\n' - 'freerflag hklin cad.mtz hklout ../%s > freerflag.log\n' %self.mtz_free + - '#uniqueify cad.mtz ../{0!s}\n'.format(self.mtz_free) - ) -# os.chdir(os.path.join(self.project_directory,self.xtalID)) -# os.system(Cmds) -## os.symlink(os.path.join('Dimple',self.xtalID+'.free.mtz'),self.xtalID+'.free.mtz') - return Cmds - - def dimple(self): - os.chdir('{0!s}/{1!s}'.format(self.project_directory, self.xtalID)) - generate_Rfree_Cmds='' - if os.path.isdir('{0!s}/{1!s}/Dimple'.format(self.project_directory, self.xtalID)): - # this 'if not' step is usually not necessary; only if process was stopped in an odd way - if not os.path.isfile(self.project_directory+'/'+self.xtalID+'/'+self.mtz_free): - generate_Rfree_Cmds=self.get_Rfree() - if self.delete_old: - os.system('rm -fr Dimple') - os.mkdir('{0!s}/{1!s}/Dimple'.format(self.project_directory, self.xtalID)) - else: - return None - else: - os.mkdir('{0!s}/{1!s}/Dimple'.format(self.project_directory, self.xtalID)) - generate_Rfree_Cmds=self.get_Rfree() - os.chdir('{0!s}/{1!s}/Dimple'.format(self.project_directory, self.xtalID)) - - if self.queueing_system_available: - top_line='#PBS -joe -N XCE_dimple' - else: - top_line='#!'+os.getenv('SHELL') - - if 'csh' in os.getenv('SHELL'): - ccp4_scratch='setenv CCP4_SCR '+self.ccp4_scratch_directory+'\n' - elif 'bash' in os.getenv('SHELL'): - ccp4_scratch='export CCP4_SCR='+self.ccp4_scratch_directory+'\n' - else: - ccp4_scratch='' - - ################################################################################ - # in case additional ligands are present in the reference.pdb file, - # the user needs to provide the following files: - # - .pdb - # - .cif # this file contains restraints for all the ligands in the respective pdb file - - if os.path.isfile(self.reference+'.cif'): - ref_lib=' --libin '+self.reference+'.cif' - else: - ref_lib='' - - Cmds = ( - '{0!s}\n'.format(top_line)+ - generate_Rfree_Cmds+ - '\n' - 'cd %s/%s/Dimple\n' %(self.project_directory,self.xtalID) + - '\n' - +ccp4_scratch+ - '\n' - 'dimple %s ../%s %s.pdb dimple' %(ref_lib,self.mtz_free,self.reference) + - '\n' - 'cd %s/%s\n' %(self.project_directory,self.xtalID) + - '\n' - '/bin/rm refine.pdb\n' - '/bin/rm refine.mtz\n' - 'ln -s Dimple/dimple/final.pdb refine.pdb\n' - 'ln -s Dimple/dimple/final.mtz refine.mtz\n' - '\n' - 'fft hklin refine.mtz mapout 2fofc.map << EOF\n' - ' labin F1=2FOFCWT PHI=PH2FOFCWT\n' - 'EOF\n' - '\n' - 'fft hklin refine.mtz mapout fofc.map << EOF\n' - ' labin F1=FOFCWT PHI=PHFOFCWT\n' - 'EOF\n' - '\n' - 'fft hklin refine.mtz mapout 2fofc.map << EOF\n' - ' labin F1=FWT PHI=PHWT\n' - 'EOF\n' - '\n' - 'fft hklin refine.mtz mapout fofc.map << EOF\n' - ' labin F1=DELFWT PHI=PHDELWT\n' - 'EOF\n' - '\n' - '/bin/rm dimple_run_in_progress\n' - ) - - self.Run(Cmds) - - - - def Run(self,Cmds): - os.chdir(self.project_directory+'/'+self.xtalID) - os.system('touch dimple_run_in_progress') - os.chdir(self.project_directory+'/'+self.xtalID+'/Dimple') - f = open('xce_dimple.sh','w') - f.write(Cmds) - f.close() - if self.queueing_system_available: - os.system('qsub xce_dimple.sh') - else: - os.system('chmod +x xce_dimple.sh') - os.system('./xce_dimple.sh') - -class helpers: - - - def __init__(self): - try: - # this sys path append is only meaningful if non-CCP4 python is used to launch XCE -# sys.path.append(os.path.join(os.getenv('CCP4'),'lib','python2.7','site-packages')) - from rdkit import Chem - from rdkit.Chem import AllChem - from rdkit.Chem import Draw - self.pil_rdkit_present=True - except ImportError: - self.pil_rdkit_present=False - pass - - def pil_rdkit_exist(self): - return self.pil_rdkit_present - - def make_png(self,initial_model_directory,sample,compoundID,smiles,external_software,database_directory,data_source_file,ccp4_scratch_directory,counter,xce_logfile,restraints_program): - Logfile=XChemLog.updateLog(xce_logfile) - -# if not os.path.isfile(os.path.join(initial_model_directory,sample,'compound','ACEDRG_IN_PROGRESS')): - os.system('touch RESTRAINTS_IN_PROGRESS') - - header='#!'+os.getenv('SHELL')+'\n' - if external_software['qsub']: - if not external_software['qsub_array']: - header='#PBS -joe -N xce_acedrg\n' - - # check if CompoundSMILEScovalent field is not Null - # CompoundSMILESproduct can be used to create only a CIF file for the product to make fitting easier - # however, the complete smiles string will be used to make the png file - productSmiles = None - db = XChemDB.data_source(os.path.join(database_directory,data_source_file)) - sql = "select CompoundSMILESproduct from mainTable where CrystalName = '%s'" %sample - query = db.execute_statement(sql) - productSmiles = query[0][0] - if str(productSmiles).replace(' ','') == '': - productSmiles = smiles - elif 'none' in str(productSmiles).lower(): - productSmiles = smiles - elif 'null' in str(productSmiles).lower(): - productSmiles = smiles - else: - productSmiles = str(productSmiles) - - software='' - if restraints_program=='acedrg': - if os.path.isfile(os.path.join(initial_model_directory,sample,'old.cif')): - software='acedrg --res LIG -c ../old.cif -o {0!s}\n'.format((compoundID.replace(' ',''))) - else: - software='acedrg --res LIG -i "{0!s}" -o {1!s}\n'.format(productSmiles, compoundID.replace(' ','')) - elif restraints_program=='phenix.elbow': - if os.path.isfile(os.path.join(initial_model_directory,sample,'old.cif')): - software='phenix.elbow --file=../old.cif --id LIG --output {0!s}\n'.format((compoundID.replace(' ',''))) - else: - software='phenix.elbow --smiles="{0!s}" --id LIG --output {1!s}\n'\ - .format(productSmiles, compoundID.replace(' ','')) - elif restraints_program=='grade': - if os.getcwd().startswith('/dls'): - software+='module load buster\n' - software+="export BDG_TOOL_OBABEL='none'\n" - if os.path.isfile(os.path.join(initial_model_directory,sample,'old.cif')): - software+='grade -resname LIG -nomogul -in ../old.cif -ocif {0!s}.cif -opdb {1!s}.pdb\n'\ - .format(compoundID.replace(' ',''), compoundID.replace(' ','')) - else: - software+='grade -resname LIG -nomogul "{0!s}" -ocif {1!s}.cif -opdb {2!s}.pdb\n'\ - .format(productSmiles, compoundID.replace(' ',''), compoundID.replace(' ','')) - # Removal of the hydrogen atoms in PDB files is required for REFMAC 5 run. With hydrogens some ligands fail to - # pass the external restraints in pandda.giant.make_restraints. - # Copy the file with hydrogens to retain in case needed - - check_stereochemistry = '' - - copy_with_hydrogens = 'cp {0!s}.pdb {0!s}_with_H.pdb'.format(compoundID.replace(' ', '')) - - strip_hydrogens = 'phenix.reduce {0!s}.pdb -trim > {0!s}_tmp.pdb'.format(compoundID.replace(' ', '')) - - Cmds = ( - - header + - '\n' - 'export XChemExplorer_DIR="' + os.getenv('XChemExplorer_DIR') + '"' + - '\n' - 'source $XChemExplorer_DIR/setup-scripts/xce.setup-sh' - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/update_status_flag.py {0!s} {1!s} {2!s} {3!s}' - .format(os.path.join(database_directory, data_source_file), sample, 'RefinementCIFStatus', 'running') + - '\n' - '$CCP4/bin/ccp4-python {0!s} "{1!s}" {2!s} {3!s} {4!s}\n' - .format(os.path.join(os.getenv('XChemExplorer_DIR'), 'helpers','create_png_of_compound.py'), - smiles, compoundID.replace(' ', ''), sample, initial_model_directory) + - '\n' - 'cd ' + os.path.join(initial_model_directory, sample, 'compound') + - '\n' - + software + - '\n' - '$CCP4/bin/ccp4-python $XChemExplorer_DIR/helpers/assign_stereochemistry.py {0!s} {1!s} {2!s}' - .format(compoundID.replace(' ',''),os.path.join(initial_model_directory,sample), os.path.join(database_directory,data_source_file)) + - '\n' - + copy_with_hydrogens + - '\n' - + strip_hydrogens + - '\n' - 'mv {0!s}_tmp.pdb {0!s}.pdb'.format(compoundID.replace(' ', '')) + - '\n' - 'rm -f {0!s}_tmp.pdb'.format(compoundID.replace(' ', '')) + - '\n' - 'cd ' + os.path.join(initial_model_directory, sample) + - '\n' - 'ln -s compound/%s.cif .\n' % compoundID.replace(' ', '') + - 'ln -s compound/{0!s}.pdb .\n'.format(compoundID.replace(' ', '')) + - 'ln -s compound/{0!s}.png .\n'.format(compoundID.replace(' ', '')) + - '\n' - '$CCP4/bin/ccp4-python ' + os.path.join(os.getenv('XChemExplorer_DIR'), 'helpers', - 'update_data_source_for_new_cif_files.py') + - ' {0!s} {1!s} {2!s} {3!s}\n'.format(os.path.join(database_directory, data_source_file), sample, - initial_model_directory, compoundID.replace(' ', '')) + - '\n' - '/bin/rm -f compound/RESTRAINTS_IN_PROGRESS\n' - ) - - - os.chdir(ccp4_scratch_directory) - Logfile.insert('creating ACEDRG shell script for {0!s},{1!s} in {2!s}'.format(sample, compoundID, ccp4_scratch_directory)) - print Cmds - print 'ccp4_scratch',ccp4_scratch_directory - f = open('xce_acedrg_{0!s}.sh'.format(str(counter)),'w') - f.write(Cmds) - f.close() - os.system('chmod +x xce_acedrg_{0!s}.sh'.format(str(counter))) - - - -# if queueing_system_available: -# os.system('qsub acedrg.sh') -# else: -# os.system('chmod +x acedrg.sh') -# os.system('./acedrg.sh') - -# os.chdir(os.path.join(initial_model_directory,sample)) -# if os.path.isfile(os.path.join(initial_model_directory,sample,'compound',compoundID.replace(' ','')+'.pdb'))\ -# and not os.path.isfile(os.path.join(initial_model_directory,sample,compoundID.replace(' ','')+'.pdb')): -# os.symlink(os.path.join(initial_model_directory,sample,'compound',compoundID.replace(' ','')+'.pdb'),compoundID.replace(' ','')+'.pdb') -# if os.path.isfile(os.path.join(initial_model_directory,sample,'compound',compoundID.replace(' ','')+'.cif'))\ -# and not os.path.isfile(os.path.join(initial_model_directory,sample,compoundID.replace(' ','')+'.cif')): -# os.symlink(os.path.join(initial_model_directory,sample,'compound',compoundID.replace(' ','')+'.cif'),compoundID.replace(' ','')+'.cif') -# if os.path.isfile(os.path.join(initial_model_directory,sample,'compound',compoundID.replace(' ','')+'.png'))\ -# and not os.path.isfile(os.path.join(initial_model_directory,sample,compoundID.replace(' ','')+'.png')): -# os.symlink(os.path.join(initial_model_directory,sample,'compound',compoundID.replace(' ','')+'.png'),compoundID.replace(' ','')+'.png') - - -class parse: - - def __init__(self): - self.space_group_dict= { 'triclinic': ['P1'], -# 'monoclinic': ['P2','P21','C121','P1211','P121'], - 'monoclinic_P': ['P2','P21','P1211','P121'], - 'monoclinic_C': ['C2','C121'], - 'orthorhombic': ['P222','P2122','P2212','P2221', - 'P21212','P21221','P22121','P212121', - 'C222','C2221', - 'F222', 'I222', 'I212121'], - 'tetragonal': ['P4','P41','P42','P43','I4','I41', - 'P422','P4212','P4122','P41212','P4222', - 'P42212','P4322','P43212','I422','I4122' ], - 'hexagonal': ['P3','P31','P32', - 'P312','P321','P3112','P3121','P3212','P3221', - 'P6','P61','P65','P62','P64','P63', - 'P622','P6122','P6522','P6222','P6422','P6322' ], - 'rhombohedral': ['H3','H32'], - 'cubic': ['P23','F23','I23','P213','I213', - 'P432','P4232','F432','F4132','I432','P4332','P4132','I4132' ] } - - self.point_group_dict= { '1': ['P1'], - '2': ['P2','P21','C121','P1211','P121','C2'], - '222': ['P222','P2122','P2212','P2221', - 'P21212','P21221','P22121','P212121', - 'C222','C2221', - 'F222', 'I222', 'I212121'], - '4': ['P4','P41','P42','P43','I4','I41'], - '422': ['P422','P4212','P4122','P41212','P4222', - 'P42212','P4322','P43212','I422','I4122' ], - '3': ['P3','P31','P32','H3'], - '32': ['P312','P321','P3112','P3121','P3212','P3221','H32'], - '6': ['P6','P61','P65','P62','P64','P63'], - '622': ['P622','P6122','P6522','P6222','P6422','P6322' ], - '23': ['P23','F23','I23','P213','I213'], - '432': ['P432','P4232','F432','F4132','I432','P4332','P4132','I4132' ] } - - self.nr_asu_in_unitcell_for_point_group = { '1': 1, - '2': 2, - '222': 4, - '4': 4, - '422': 8, - '3': 3, - '32': 6, - '6': 6, - '622': 12, - '23': 12, - '432': 24 } - - self.aimless = { 'DataProcessingProgram': 'n/a', - 'DataCollectionRun': 'n/a', - 'DataProcessingSpaceGroup': 'n/a', - 'DataProcessingUnitCell': 'n/a', - 'DataProcessingA': 'n/a', - 'DataProcessingB': 'n/a', - 'DataProcessingC': 'n/a', - 'DataProcessingAlpha': 'n/a', - 'DataProcessingBeta': 'n/a', - 'DataProcessingGamma': 'n/a', - 'DataProcessingResolutionLow': 'n/a', - 'DataProcessingResolutionLowInnerShell': 'n/a', - 'DataProcessingResolutionHigh': 'n/a', - 'DataProcessingResolutionHighOuterShell': 'n/a', - 'DataProcessingResolutionOverall': 'n/a', - 'DataProcessingRmergeOverall': 'n/a', - 'DataProcessingRmergeLow': 'n/a', - 'DataProcessingRmergeHigh': 'n/a', - 'DataProcessingIsigOverall': 'n/a', - 'DataProcessingIsigLow': 'n/a', - 'DataProcessingIsigHigh': 'n/a', - 'DataProcessingCompletenessOverall': 'n/a', - 'DataProcessingCompletenessLow': 'n/a', - 'DataProcessingCompletenessHigh': 'n/a', - 'DataProcessingMultiplicityOverall': 'n/a', - 'DataProcessingMultiplicityLow': 'n/a', - 'DataProcessingMultiplicityHigh': 'n/a', - 'DataProcessingCChalfOverall': 'n/a', - 'DataProcessingCChalfLow': 'n/a', - 'DataProcessingCChalfHigh': 'n/a', - 'DataProcessingResolutionHigh15sigma': 'n/a', - 'DataProcessingUniqueReflectionsOverall': 'n/a', - 'DataProcessingLattice': 'n/a', - 'DataProcessingPointGroup': 'n/a', - 'DataProcessingUnitCellVolume': 0, - 'DataProcessingAlert': '#FF0000', - 'DataCollectionWavelength': 'n/a', - 'DataProcessingScore': 'n/a' } - - - - def GetAimlessLog(self,Logfile): - self.Logfile=Logfile - Aimless = { 'AutoProc': 'n/a', - 'Run': 'n/a', - 'SpaceGroup': 'n/a', - 'UnitCell': 'n/a', - 'ResolutionLow': 'n/a', - 'ResolutionLowInnerShell': 'n/a', - 'ResolutionHigh': 'n/a', - 'ResolutionHighOuterShell': 'n/a', - 'RmergeOverall': 'n/a', - 'RmergeLow': 'n/a', - 'RmergeHigh': 'n/a', - 'IsigOverall': 'n/a', - 'IsigLow': 'n/a', - 'IsigHigh': 'n/a', - 'CompletenessOverall': 'n/a', - 'CompletenessLow': 'n/a', - 'CompletenessHigh': 'n/a', - 'MultiplicityOverall': 'n/a', - 'MultiplicityLow': 'n/a', - 'MultiplicityHigh': 'n/a', - 'UniqueReflectionsOverall': 'n/a', - 'Lattice': 'n/a', - 'UnitCellVolume': 0, - 'Alert': '#FF0000' } - - spg='n/a' - a='n/a' - b='n/a' - c='n/a' - alpha='n/a' - beta='n/a' - gamma='n/a' - - if 'fast_dp' in self.Logfile: - Aimless['AutoProc']='fast_dp' - if '3d-run' in self.Logfile: - Aimless['AutoProc']='xia2 3d' - if '3dii-run' in self.Logfile: - Aimless['AutoProc']='xia2 3dii' - if 'dials-run' in self.Logfile: - Aimless['AutoProc']='dials' - if 'autoPROC' in self.Logfile: - Aimless['AutoProc']='autoPROC' - - # get run number from logfile - # Note: only works if file is in original directory, but not once it lifes in 'inital_model' -# print self.Logfile.split('/')[9].split('_')[1] -# if len(self.Logfile.split('/'))>8 and len(self.Logfile.split('/')[9].split('_'))==1: - try: - Aimless['Run']=self.Logfile.split('/')[9].split('_')[1] - except IndexError: - pass - - for line in open(self.Logfile): - if line.startswith('Low resolution limit') and len(line.split())==6: - Aimless['ResolutionLow'] = line.split()[3] - Aimless['ResolutionHighOuterShell'] = line.split()[5] - if line.startswith('High resolution limit') and len(line.split())==6: - Aimless['ResolutionHigh'] = line.split()[3] - Aimless['ResolutionLowInnerShell'] = line.split()[4] - if line.startswith('Rmerge (all I+ and I-)') and len(line.split())==8: - Aimless['RmergeOverall'] = line.split()[5] - Aimless['RmergeLow'] = line.split()[6] - Aimless['RmergeHigh'] = line.split()[7] - if line.startswith('Mean((I)/sd(I))') and len(line.split())==4: - Aimless['IsigOverall'] = line.split()[1] - Aimless['IsigHigh'] = line.split()[3] - Aimless['IsigLow'] = line.split()[2] - if line.startswith('Completeness') and len(line.split())==4: - Aimless['CompletenessOverall'] = line.split()[1] - Aimless['CompletenessHigh'] = line.split()[3] - Aimless['CompletenessLow'] = line.split()[2] - if line.startswith('Multiplicity') and len(line.split())==4: - Aimless['MultiplicityOverall'] = line.split()[1] - Aimless['MultiplicityHigh'] = line.split()[3] - Aimless['MultiplicityLow'] = line.split()[3] - if line.startswith('Average unit cell:') and len(line.split())==9: - tmp = [line.split()] - a = int(float(tmp[0][3])) - b = int(float(tmp[0][4])) - c = int(float(tmp[0][5])) - alpha = int(float(tmp[0][6])) - beta = int(float(tmp[0][7])) - gamma = int(float(tmp[0][8])) - if line.startswith('Total number unique') and len(line.split())==6: - Aimless['UniqueReflectionsOverall']=line.split()[3] - if line.startswith('Space group:'): - Aimless['SpaceGroup']=line.replace('Space group: ','')[:-1] - Aimless['Lattice']=self.get_lattice_from_space_group(Aimless['SpaceGroup']) - if a != 'n/a' and b != 'n/a' and c != 'n/a' and \ - alpha != 'n/a' and beta != 'n/a' and gamma != 'n/a' and Aimless['Lattice'] != 'n/a': - Aimless['UnitCellVolume']=self.calc_unitcell_volume_from_logfile(float(a),float(b),float(c), - math.radians(float(alpha)), - math.radians(float(beta)), - math.radians(float(gamma)), - Aimless['Lattice']) - Aimless['UnitCell']=str(a)+' '+str(b)+' '+str(c)+' '+str(alpha)+' '+str(beta)+' '+str(gamma) - - # Hex Color code: - # red: #FF0000 - # orange: #FF9900 - # green: #00FF00 - # gray: #E0E0E0 - - if Aimless['ResolutionHigh']=='n/a' or Aimless['RmergeLow'] =='n/a': - Aimless['Alert'] = '#FF0000' - else: - if float(Aimless['ResolutionHigh']) > 3.5 or float(Aimless['RmergeLow']) > 0.1: - Aimless['Alert'] = '#FF0000' - if (3.5 >= float(Aimless['ResolutionHigh']) > 2.5) or \ - (0.1 >= float(Aimless['RmergeLow']) > 0.05): - Aimless['Alert'] = '#FF9900' - if float(Aimless['ResolutionHigh']) <= 2.5 and float(Aimless['RmergeLow']) <= 0.05: - Aimless['Alert'] = '#00FF00' - - return Aimless - - def return_empty_aimless_dict_for_db(self): - return self.aimless - - def read_aimless_logfile(self,logfile): - # essentially same as above, but compatible with datasource - # will hopefully supersede function above - - spg='n/a' - a='n/a' - b='n/a' - c='n/a' - alpha='n/a' - beta='n/a' - gamma='n/a' - - if 'fast_dp' in logfile: - self.aimless['DataProcessingProgram']='fast_dp' - elif '3d-run' in logfile: - self.aimless['DataProcessingProgram']='xia2 3d' - elif '3dii-run' in logfile: - self.aimless['DataProcessingProgram']='xia2 3dii' - elif 'dials-run' in logfile: - self.aimless['DataProcessingProgram']='dials' - elif 'autoPROC' in logfile: - self.aimless['DataProcessingProgram']='autoPROC' - elif 'staraniso' in logfile: - self.aimless['DataProcessingProgram']='aP_staraniso' - - # get run number from logfile - # Note: only works if file is in original directory, but not once it moved to 'inital_model' folder# -## print self.Logfile.split('/')[9].split('_')[1] -## if len(self.Logfile.split('/'))>8 and len(self.Logfile.split('/')[9].split('_'))==1: - try: - self.aimless['DataCollectionRun']=logfile.split('/')[9].split('_')[1] - except IndexError: - pass - - resolution_at_15_sigma_line_overall_found=False - resolution_at_20_sigma_line_overall_found=False - - -# -# print '=====>',self.aimless['DataCollectionRun'],logfile -# - resolution_at_sigma_line_overall_found=False - for line_number,line in enumerate(open(logfile)): -# if 'Wavelength' in line: -# print 'here' -# print line.split() - if 'Wavelength' in line and len(line.split()) >= 2: - self.aimless['DataCollectionWavelength']=line.split()[1] - if 'Low resolution limit' in line and len(line.split())==6: - self.aimless['DataProcessingResolutionLow'] = line.split()[3] - self.aimless['DataProcessingResolutionHighOuterShell'] = line.split()[5] - if 'High resolution limit' in line and len(line.split())==6: - self.aimless['DataProcessingResolutionHigh'] = line.split()[3] - self.aimless['DataProcessingResolutionLowInnerShell'] = line.split()[4] - if 'Rmerge (all I+ and I-)' in line and len(line.split())==8: - self.aimless['DataProcessingRmergeOverall'] = line.split()[5] - self.aimless['DataProcessingRmergeLow'] = line.split()[6] - self.aimless['DataProcessingRmergeHigh'] = line.split()[7] - if 'Rmerge (all I+ & I-)' in line and len(line.split())==8: - self.aimless['DataProcessingRmergeOverall'] = line.split()[5] - self.aimless['DataProcessingRmergeLow'] = line.split()[6] - self.aimless['DataProcessingRmergeHigh'] = line.split()[7] - if 'Mean((I)/sd(I))' in line and len(line.split())==4: - self.aimless['DataProcessingIsigOverall'] = line.split()[1] - self.aimless['DataProcessingIsigHigh'] = line.split()[3] - self.aimless['DataProcessingIsigLow'] = line.split()[2] - if 'Mean(I)/sd(I)' in line and len(line.split())==4: - self.aimless['DataProcessingIsigOverall'] = line.split()[1] - self.aimless['DataProcessingIsigHigh'] = line.split()[3] - self.aimless['DataProcessingIsigLow'] = line.split()[2] - if line.startswith('Completeness') and len(line.split())==4: - self.aimless['DataProcessingCompletenessOverall'] = line.split()[1] - self.aimless['DataProcessingCompletenessHigh'] = line.split()[3] - self.aimless['DataProcessingCompletenessLow'] = line.split()[2] - if 'Completeness (ellipsoidal)' in line and len(line.split())==5: - self.aimless['DataProcessingCompletenessOverall'] = line.split()[2] - self.aimless['DataProcessingCompletenessHigh'] = line.split()[4] - self.aimless['DataProcessingCompletenessLow'] = line.split()[3] - if 'Multiplicity' in line and len(line.split())==4: - self.aimless['DataProcessingMultiplicityOverall'] = line.split()[1] - self.aimless['DataProcessingMultiplicityHigh'] = line.split()[3] - self.aimless['DataProcessingMultiplicityLow'] = line.split()[3] - if line.startswith('Mn(I) half-set correlation CC(1/2)') and len(line.split())==7: - self.aimless['DataProcessingCChalfOverall'] = line.split()[4] - self.aimless['DataProcessingCChalfLow'] = line.split()[5] - self.aimless['DataProcessingCChalfHigh'] = line.split()[6] - if line.startswith(' CC(1/2)') and len(line.split())==4: - self.aimless['DataProcessingCChalfOverall'] = line.split()[1] - self.aimless['DataProcessingCChalfLow'] = line.split()[2] - self.aimless['DataProcessingCChalfHigh'] = line.split()[3] - if line.startswith('Estimates of resolution limits: overall'): - resolution_at_15_sigma_line_overall_found=True - resolution_at_20_sigma_line_overall_found=True - if resolution_at_15_sigma_line_overall_found: - if 'from Mn(I/sd)' in line and len(line.split()) >= 7: - if '1.5' in line.split()[3]: - self.aimless['DataProcessingResolutionHigh15sigma']=line.split()[6][:-1] - resolution_at_15_sigma_line_overall_found=False - if resolution_at_20_sigma_line_overall_found: - if 'from Mn(I/sd)' in line and len(line.split()) >= 7: - if '2.0' in line.split()[3]: - self.aimless['DataProcessingResolutionHigh20sigma']=line.split()[6][:-1] - resolution_at_20_sigma_line_overall_found=False - if (line.startswith('Average unit cell:') or line.startswith(' Unit cell parameters')) and len(line.split())==9: - tmp = [line.split()] - a = int(float(tmp[0][3])) - b = int(float(tmp[0][4])) - c = int(float(tmp[0][5])) - alpha = int(float(tmp[0][6])) - beta = int(float(tmp[0][7])) - gamma = int(float(tmp[0][8])) - self.aimless['DataProcessingA']=str(a) - self.aimless['DataProcessingB']=str(b) - self.aimless['DataProcessingC']=str(c) - self.aimless['DataProcessingAlpha']=str(alpha) - self.aimless['DataProcessingBeta']=str(beta) - self.aimless['DataProcessingGamma']=str(gamma) - if 'Total number unique' in line and len(line.split())==6: - self.aimless['DataProcessingUniqueReflectionsOverall']=line.split()[3] - if line.startswith('Space group:') or line.startswith(' Spacegroup name'): - if 'Laue' in line: - continue - if 'Spacegroup name' in line: - self.aimless['DataProcessingSpaceGroup'] = line.replace(' Spacegroup name', '')[:-1].replace(' ','') - else: - self.aimless['DataProcessingSpaceGroup']=line.replace('Space group: ','')[:-1] - self.aimless['DataProcessingLattice']=self.get_lattice_from_space_group(self.aimless['DataProcessingSpaceGroup']) - self.aimless['DataProcessingPointGroup']=self.get_pointgroup_from_space_group(self.aimless['DataProcessingSpaceGroup']) -# print a,b,c,alpha,beta,gamma,self.aimless['DataProcessingLattice'] - if a != 'n/a' and b != 'n/a' and c != 'n/a' and \ - alpha != 'n/a' and beta != 'n/a' and gamma != 'n/a' and self.aimless['DataProcessingLattice'] != 'n/a': - self.aimless['DataProcessingUnitCellVolume']=str(self.calc_unitcell_volume_from_logfile(float(a),float(b),float(c), - math.radians(float(alpha)), - math.radians(float(beta)), - math.radians(float(gamma)), - self.aimless['DataProcessingLattice'])) - try: - high_symmetry_boost=self.nr_asu_in_unitcell_for_point_group[self.aimless['DataProcessingPointGroup']] - self.aimless['DataProcessingScore'] = (float(self.aimless['DataProcessingUniqueReflectionsOverall'])*\ - float(self.aimless['DataProcessingCompletenessOverall'])*\ - high_symmetry_boost*\ - float(self.aimless['DataProcessingIsigOverall']))/float(self.aimless['DataProcessingUnitCellVolume']) - except ValueError: - self.aimless['DataProcessingScore']=0.0 - self.aimless['DataProcessingUnitCell']=str(a)+' '+str(b)+' '+str(c)+' '+str(alpha)+' '+str(beta)+' '+str(gamma) - self.aimless['DataProcessingResolutionOverall']=str(self.aimless['DataProcessingResolutionLow'])+' - '+str(self.aimless['DataProcessingResolutionHigh']) - - # Hex Color code: - # red: #FF0000 - # orange: #FF9900 - # green: #00FF00 - # gray: #E0E0E0 - - if self.aimless['DataProcessingResolutionHigh']=='n/a' or self.aimless['DataProcessingRmergeLow'] =='n/a': - self.aimless['DataProcessingAlert'] = '#FF0000' - else: - if float(self.aimless['DataProcessingResolutionHigh']) > 3.5 or float(self.aimless['DataProcessingRmergeLow']) > 0.1: - self.aimless['DataProcessingAlert'] = '#FF0000' - if (3.5 >= float(self.aimless['DataProcessingResolutionHigh']) > 2.5) or \ - (0.1 >= float(self.aimless['DataProcessingRmergeLow']) > 0.05): - self.aimless['DataProcessingAlert'] = '#FF9900' - if float(self.aimless['DataProcessingResolutionHigh']) <= 2.5 and float(self.aimless['DataProcessingRmergeLow']) <= 0.05: - self.aimless['DataProcessingAlert'] = '#00FF00' - - return self.aimless - - - - - def get_lattice_from_space_group(self,logfile_spacegroup): - lattice_type='n/a' - for lattice in self.space_group_dict: - for spacegroup in self.space_group_dict[lattice]: - if logfile_spacegroup.replace(' ','')==spacegroup: - lattice_type=lattice - break - return lattice_type - - def get_pointgroup_from_space_group(self,logfile_spacegroup): - pointgroup='n/a' - for pg in self.point_group_dict: - for spacegroup in self.point_group_dict[pg]: - if logfile_spacegroup.replace(' ','')==spacegroup: - pointgroup=pg - break - return pointgroup - - - - def calc_unitcell_volume_from_logfile(self,a,b,c,alpha,beta,gamma,lattice): - unitcell_volume=0 - if lattice=='triclinic': - unitcell_volume=a*b*c* \ - math.sqrt((1-math.cos(alpha)**2-math.cos(beta)**2-math.cos(gamma)**2) \ - +2*(math.cos(alpha)*math.cos(beta)*math.cos(gamma))) -# if lattice=='monoclinic': - if 'monoclinic' in lattice: - unitcell_volume=round(a*b*c*math.sin(beta),1) - if lattice=='orthorhombic' or lattice=='tetragonal' or lattice=='cubic': - unitcell_volume=round(a*b*c,1) - if lattice=='hexagonal' or lattice=='rhombohedral': - unitcell_volume=round(a*b*c*(math.sin(math.radians(60))),1) - return unitcell_volume - -# def get_all_values_as_dict(self): -# info = { 'unitcell': 'n/a', -# 'spacegroup': 'n/a', -# 'unitcell_volume': 'n/a', -# 'bravais_lattice': 'n/a' } - - - - - - def PDBheader(self,pdbfile): - PDBinfo = { 'Rcryst': 'n/a', - 'RcrystTL': 'gray', - 'Rfree': 'n/a', - 'RfreeTL': 'gray', - 'SpaceGroup': 'n/a', - 'PointGroup': 'n/a', - 'UnitCell': 'n/a', - 'ResolutionHigh': 'n/a', - 'ResolutionColor': 'gray', - 'Lattice': 'n/a', - 'UnitCellVolume': 0, - 'Alert': '#E0E0E0', - 'rmsdBonds': 'n/a', - 'rmsdBondsTL': 'gray', - 'rmsdAngles': 'n/a', - 'rmsdAnglesTL': 'gray'} - - a='n/a' - b='n/a' - c='n/a' - alpha='n/a' - beta='n/a' - gamma='n/a' - - if os.path.isfile(pdbfile): - for line in open(pdbfile): - try: - if line.startswith('REMARK 3 R VALUE (WORKING + TEST SET) :'): - PDBinfo['Rcryst']=line.split()[9] - if float(PDBinfo['Rcryst']) > 0.4: - PDBinfo['Alert']='#FF0000' - PDBinfo['RcrystTL'] = 'red' - if 0.4 >= float(PDBinfo['Rcryst']) >= 0.3: - PDBinfo['Alert']='#FF9900' - PDBinfo['RcrystTL'] = 'orange' - if float(PDBinfo['Rcryst']) < 0.3: - PDBinfo['Alert']='#00FF00' - PDBinfo['RcrystTL'] = 'green' - if line.startswith('REMARK 3 FREE R VALUE :'): - PDBinfo['Rfree']=line.split()[6] - if float(PDBinfo['Rfree']) > 0.4: - PDBinfo['Alert']='#FF0000' - PDBinfo['RfreeTL'] = 'red' - if 0.4 >= float(PDBinfo['Rfree']) >= 0.3: - PDBinfo['Alert']='#FF9900' - PDBinfo['RfreeTL'] = 'orange' - if float(PDBinfo['Rfree']) < 0.3: - PDBinfo['Alert']='#00FF00' - PDBinfo['RfreeTL'] = 'green' - except ValueError: - pass - - if line.startswith('REMARK 3 RESOLUTION RANGE HIGH (ANGSTROMS) :'): - PDBinfo['ResolutionHigh']=line.split()[7] - try: - if float(line.split()[7]) < 2.4: PDBinfo['ResolutionColor'] = 'green' - if 2.4 <= float(line.split()[7]) < 2.8: PDBinfo['ResolutionColor'] = 'orange' - if float(line.split()[7]) >= 2.8: PDBinfo['ResolutionColor'] = 'red' - except ValueError: - pass - if line.startswith('REMARK 3 BOND LENGTHS REFINED ATOMS (A):'): - PDBinfo['rmsdBonds'] = line.split()[9] - try: - if float(line.split()[9]) < 0.02: PDBinfo['rmsdBondsTL'] = 'green' - if 0.02 <= float(line.split()[9]) < 0.03: PDBinfo['rmsdBondsTL'] = 'orange' - if float(line.split()[9]) >= 0.03: PDBinfo['rmsdBondsTL'] = 'red' - except ValueError: - pass - if line.startswith('REMARK 3 BOND ANGLES REFINED ATOMS (DEGREES):'): - PDBinfo['rmsdAngles'] = line.split()[9] - try: - if float(line.split()[9]) < 2.0: PDBinfo['rmsdAnglesTL'] = 'green' - if 2.0 <= float(line.split()[9]) < 3.0: PDBinfo['rmsdAnglesTL'] = 'orange' - if float(line.split()[9]) >= 3.0: PDBinfo['rmsdAnglesTL'] = 'red' - except ValueError: - pass - - if line.startswith('CRYST1'): - a=int(float(line.split()[1])) - b=int(float(line.split()[2])) - c=int(float(line.split()[3])) - alpha=int(float(line.split()[4])) - beta=int(float(line.split()[5])) - gamma=int(float(line.split()[6])) - - PDBinfo['UnitCell']=line.split()[1]+' '+line.split()[2]+' '+line.split()[3]+' '+ \ - line.split()[4]+' '+line.split()[5]+' '+line.split()[6] -# PDBinfo['SpaceGroup']=line[55:len(line)-1].replace(' ','').rstrip('\r') - PDBinfo['SpaceGroup']=str(line[55:65]).rstrip() - - PDBinfo['Lattice']=self.get_lattice_from_space_group(PDBinfo['SpaceGroup']) - PDBinfo['PointGroup']=self.get_pointgroup_from_space_group(PDBinfo['SpaceGroup']) - if a != 'n/a' and b != 'n/a' and c != 'n/a' and \ - alpha != 'n/a' and beta != 'n/a' and gamma != 'n/a' and PDBinfo['Lattice'] != 'n/a': - PDBinfo['UnitCellVolume']=self.calc_unitcell_volume_from_logfile(float(a),float(b),float(c), - math.radians(float(alpha)), - math.radians(float(beta)), - math.radians(float(gamma)), - PDBinfo['Lattice']) - - - - return PDBinfo - - - def dict_for_datasource_update(self,pdbfile): - pdb = self.PDBheader(pdbfile) - db_dict= {'RefinementPDB_latest': os.path.realpath(pdbfile), 'RefinementRcryst': pdb['Rcryst'], - 'RefinementRcrystTraficLight': pdb['RcrystTL'], 'RefinementRfree': pdb['Rfree'], - 'RefinementRfreeTraficLight': pdb['RfreeTL'], 'RefinementRmsdBonds': pdb['rmsdBonds'], - 'RefinementRmsdBondsTL': pdb['rmsdBondsTL'], 'RefinementRmsdAngles': pdb['rmsdAngles'], - 'RefinementRmsdAnglesTL': pdb['rmsdAnglesTL'], 'RefinementSpaceGroup': pdb['SpaceGroup'], - 'RefinementResolution': pdb['ResolutionHigh'], 'RefinementResolutionTL': pdb['ResolutionColor']} - return db_dict - - - - def update_datasource_with_PDBheader(self,xtal,datasource,pdbfile): - pdb = self.PDBheader(pdbfile) - db_dict= {'RefinementPDB_latest': os.path.realpath(pdbfile), 'RefinementRcryst': pdb['Rcryst'], - 'RefinementRcrystTraficLight': pdb['RcrystTL'], 'RefinementRfree': pdb['Rfree'], - 'RefinementRfreeTraficLight': pdb['RfreeTL'], 'RefinementRmsdBonds': pdb['rmsdBonds'], - 'RefinementRmsdBondsTL': pdb['rmsdBondsTL'], 'RefinementRmsdAngles': pdb['rmsdAngles'], - 'RefinementRmsdAnglesTL': pdb['rmsdAnglesTL'], 'RefinementSpaceGroup': pdb['SpaceGroup'], - 'RefinementResolution': pdb['ResolutionHigh'], 'RefinementResolutionTL': pdb['ResolutionColor']} - print db_dict - db=XChemDB.data_source(datasource) - db.update_data_source(xtal,db_dict) - - def update_datasource_with_phenix_validation_summary(self,xtal,datasource,validation_summary): - db_dict={} - if os.path.isfile(validation_summary): - for line in open(validation_summary): - if 'molprobity score' in line.lower(): - if len(line.split()) >= 4: - db_dict['RefinementMolProbityScore'] = line.split()[3] - if float(line.split()[3]) < 2: - db_dict['RefinementMolProbityScoreTL'] = 'green' - if 2 <= float(line.split()[3]) < 3: - db_dict['RefinementMolProbityScoreTL'] = 'orange' - if float(line.split()[3]) >= 3: - db_dict['RefinementMolProbityScoreTL'] = 'red' - - if 'ramachandran outliers' in line.lower(): - if len(line.split()) >= 4: - db_dict['RefinementRamachandranOutliers'] = line.split()[3] - if float(line.split()[3]) < 0.3: - db_dict['RefinementRamachandranOutliersTL'] = 'green' - if 0.3 <= float(line.split()[3]) < 1: - db_dict['RefinementRamachandranOutliersTL'] = 'orange' - if float(line.split()[3]) >= 1: - db_dict['RefinementRamachandranOutliersTL'] = 'red' - - if 'favored' in line.lower(): - if len(line.split()) >= 3: - db_dict['RefinementRamachandranFavored'] = line.split()[2] - if float(line.split()[2]) < 90: - db_dict['RefinementRamachandranFavoredTL'] = 'red' - if 90 <= float(line.split()[2]) < 98: - db_dict['RefinementRamachandranFavoredTL'] = 'orange' - if float(line.split()[2]) >= 98: - db_dict['RefinementRamachandranFavoredTL'] = 'green' - else: - db_dict['RefinementMolProbityScore'] = '-' - db_dict['RefinementMolProbityScoreTL'] = 'gray' - db_dict['RefinementRamachandranOutliers'] = '-' - db_dict['RefinementRamachandranOutliersTL'] = 'gray' - db_dict['RefinementRamachandranFavored'] = '-' - db_dict['RefinementRamachandranFavoredTL'] = 'gray' - db=XChemDB.data_source(datasource) - db.update_data_source(xtal,db_dict) - -class mtztools: - - def __init__(self,mtzfile): - self.mtzfile=mtzfile - self.hkl = any_reflection_file(file_name=self.mtzfile) - self.miller_arrays = self.hkl.as_miller_arrays() - self.mtz = self.miller_arrays[0] - self.iotbxMTZ = mtz.object(self.mtzfile) - - self.space_group_dict= { 'triclinic': [1], -# 'monoclinic': [3,4,5], - 'monoclinic_P': [3,4], - 'monoclinic_C': [5], - 'orthorhombic': [16,17,18,19,20,21,22,23,24], - 'tetragonal': [75,76,77,78,79,80,89,90,91,92,93,94,95,96,97,98], - 'hexagonal': [143,144,145,149,150,151,152,153,154,168,169,170, - 171,172,173,177,178,179,180,181,182], - 'rhombohedral': [146,155], - 'cubic': [195,196,197,198,199, - 207,208,209,210,211,212,213,214] } - - self.translate_spg_to_number_dict = { - 'p1': 1, 'p121': 3, 'p1211': 4, 'c2': 5, 'c121': 5, 'i2': 5, 'i121': 5, 'p222': 16, - 'p2122': 17, 'p2212': 17, 'p2221': 17, 'p21212': 18, 'p21221': 18, 'p22121': 18, - 'p212121': 19, 'c2221': 20, 'c222': 21, 'f222': 22, 'i222': 23, 'i212121': 24, - 'p4': 75, 'p41': 76, 'p42': 77, 'p43': 78, 'i4': 79, 'i41': 80, - 'p422': 89, 'p4212': 90, 'p4122': 91, 'p41212': 92, 'p4222': 93, 'p42212': 94, - 'p4322': 95, 'p43212': 96, 'i422': 97, 'i4122': 98, - 'p3': 143, 'p31': 144, 'p32': 145, 'p312': 149, 'p321': 150, 'p3112': 151, 'p3121': 152, - 'p3212': 153, 'p3221': 154, 'p6': 168, 'p61': 169, 'p65': 170, 'p62': 171, 'p64': 172, 'p63': 173, - 'p622': 177, 'p6122': 178, 'p6522': 179, 'p6222': 180, 'p6422': 181, 'p6322': 182, - 'r3': 146, 'h3': 146, 'r32': 155, 'h32': 155, - 'p23': 195, 'f23': 196, 'i23': 197, 'p213': 198, 'i213': 199, - 'p432': 207, 'p4232': 208, 'f432': 209, 'f4132': 210, 'i432': 211, 'p4332': 212, - 'p4132': 213, 'i4132': 214 - } - - - self.point_group_dict= { '1': [1], - '2': [3,4,5], - '222': [16,17,18,19,20,21,22,23,24], - '4': [75,76,77,78,79,80], - '422': [89,90,91,92,93,94,95,96,97,98], - '3': [143,144,145,146], - '32': [149,150,151,152,153,154,155], - '6': [168,169,170,171,172,173], - '622': [177,178,179,180,181,182], - '23': [195,196,197,198,199], - '432': [207,208,209,210,211,212,213,214] } - - self.nr_asu_in_unitcell_for_point_group = { '1': 1, - '2': 2, - '222': 4, - '4': 4, - '422': 8, - '3': 3, - '32': 6, - '6': 6, - '622': 12, - '23': 12, - '432': 24 } - - self.aimless = { 'DataProcessingProgram': 'n/a', - 'DataCollectionRun': 'n/a', - 'DataProcessingSpaceGroup': 'n/a', - 'DataProcessingUnitCell': 'n/a', - 'DataProcessingA': 'n/a', - 'DataProcessingB': 'n/a', - 'DataProcessingC': 'n/a', - 'DataProcessingAlpha': 'n/a', - 'DataProcessingBeta': 'n/a', - 'DataProcessingGamma': 'n/a', - 'DataProcessingResolutionLow': 'n/a', - 'DataProcessingResolutionLowInnerShell': 'n/a', - 'DataProcessingResolutionHigh': 'n/a', - 'DataProcessingResolutionHighOuterShell': 'n/a', - 'DataProcessingResolutionOverall': 'n/a', - 'DataProcessingRmergeOverall': 'n/a', - 'DataProcessingRmergeLow': 'n/a', - 'DataProcessingRmergeHigh': 'n/a', - 'DataProcessingIsigOverall': 'n/a', - 'DataProcessingIsigLow': 'n/a', - 'DataProcessingIsigHigh': 'n/a', - 'DataProcessingCompletenessOverall': 'n/a', - 'DataProcessingCompletenessLow': 'n/a', - 'DataProcessingCompletenessHigh': 'n/a', - 'DataProcessingMultiplicityOverall': 'n/a', - 'DataProcessingMultiplicityLow': 'n/a', - 'DataProcessingMultiplicityHigh': 'n/a', - 'DataProcessingCChalfOverall': 'n/a', - 'DataProcessingCChalfLow': 'n/a', - 'DataProcessingCChalfHigh': 'n/a', - 'DataProcessingResolutionHigh15sigma': 'n/a', - 'DataProcessingUniqueReflectionsOverall': 'n/a', - 'DataProcessingLattice': 'n/a', - 'DataProcessingPointGroup': 'n/a', - 'DataProcessingUnitCellVolume': 0, - 'DataProcessingAlert': '#FF0000', - 'DataCollectionWavelength': 'n/a', - 'DataProcessingScore': 'n/a' } - - def get_dmin(self): - return str(round(float(self.mtz.d_min()), 2)) - - def get_wavelength(self): - wavelength = 0.0 - for crystal in self.iotbxMTZ.crystals(): - for dataset in crystal.datasets(): - if not dataset.wavelength() == 0.0: - wavelength = str(round(dataset.wavelength(),5)) - break - return wavelength - - def get_information_for_datasource(self): - db_dict={} - mtz_dict=self.get_all_values_as_dict() - pg=self.get_pointgroup_from_mtz() - if mtz_dict != {}: - db_dict['DataProcessingResolutionHigh']=mtz_dict['resolution_high'] - db_dict['DataProcessingUnitCell']=mtz_dict['unitcell'] - db_dict['DataProcessingSpaceGroup']=mtz_dict['spacegroup'] - db_dict['DataProcessingUnitCellVolume']=mtz_dict['unitcell_volume'] - db_dict['DataProcessingLattice']=mtz_dict['bravais_lattice'] - if pg != '': - db_dict['DataProcessingPointGroup']=pg - return db_dict - - def get_bravais_lattice_from_spg_number(self,number): - lattice='' - for bravaislattice in self.space_group_dict: - for spg_number in self.space_group_dict[bravaislattice]: - if spg_number==number: - lattice=bravaislattice - return lattice - - def get_point_group_from_spg_number(self,number): - pointgroup='' - for pg in self.point_group_dict: - for spg_number in self.point_group_dict[pg]: - if spg_number==number: - pointgroup=pg - return pointgroup - - - def get_unit_cell_from_mtz(self): - unitcell=[] - cell_line=100000 - a=0 - b=0 - c=0 - alpha=0 - beta=0 - gamma=0 - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' * Cell Dimensions :'): - cell_line=n+2 - if n==cell_line and len(line.split())==6: - a=line.split()[0] - b=line.split()[1] - c=line.split()[2] - alpha=line.split()[3] - beta=line.split()[4] - gamma=line.split()[5] - return [a,b,c,alpha,beta,gamma] - - def get_spg_number_from_mtz(self): - spg_number=0 - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' * Space group ='): - spg_number=int(line[line.rfind(')')-3:line.rfind(')')]) - return spg_number - - def get_spg_from_mtz(self): - spg='' - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' * Space group ='): - spg=line[line.find("'")+1:line.rfind("'")] - return spg - - def get_bravais_lattice_from_mtz(self): - bravais_lattice='' - spg_number=self.get_spg_number_from_mtz() - bravais_lattice=self.get_bravais_lattice_from_spg_number(spg_number) - return bravais_lattice - - def get_pointgroup_from_mtz(self): - pointgroup='' - spg_number=self.get_spg_number_from_mtz() - pointgroup=self.get_point_group_from_spg_number(spg_number) - return pointgroup - - def calc_unitcell_volume_from_mtz(self): - spg_number=self.get_spg_number_from_mtz() - lattice=self.get_bravais_lattice_from_spg_number(spg_number) - unitcell=self.get_unit_cell_from_mtz() - a=float(unitcell[0]) - b=float(unitcell[1]) - c=float(unitcell[2]) - alpha=math.radians(float(unitcell[3])) - beta= math.radians(float(unitcell[4])) - gamma=math.radians(float(unitcell[5])) - unitcell_volume=0 - if lattice=='triclinic': - unitcell_volume=a*b*c* \ - math.sqrt((1-math.cos(alpha)**2-math.cos(beta)**2-math.cos(gamma)**2) \ - +2*(math.cos(alpha)*math.cos(beta)*math.cos(gamma))) - if 'monoclinic' in lattice: - unitcell_volume=round(a*b*c*math.sin(beta),1) - if lattice=='orthorhombic' or lattice=='tetragonal' or lattice=='cubic': - unitcell_volume=round(a*b*c,1) - if lattice=='hexagonal' or lattice=='rhombohedral': - unitcell_volume=round(a*b*c*(math.sin(math.radians(60))),1) - return unitcell_volume - - def get_high_resolution_from_mtz(self): - resolution_high='n/a' - resolution_line=1000000 - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' * Resolution Range :'): - resolution_line=n+2 - if n==resolution_line and len(line.split())==8: - resolution_high=line.split()[5] - return resolution_high - - def get_low_resolution_from_mtz(self): - resolution_low='n/a' - resolution_line=1000000 - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' * Resolution Range :'): - resolution_line=n+2 - if n==resolution_line and len(line.split())==8: - resolution_low=line.split()[3] - return resolution_low - - def get_number_measured_reflections(self): - missing_reflections='0' - all_reflections='0' - meassured_reflections='0' - resolution_line=1000000 - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - foundTable=False - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' Col Sort Min Max Num % Mean Mean Resolution Type Column'): - foundTable=True - if foundTable and len(line.split())==12: - if line.split()[11]=='F': - missing_reflections=line.split()[4] - foundTable=False - if line.startswith(' No. of reflections used in FILE STATISTICS'): - all_reflections=line.split()[7] - break - try: - meassured_reflections=int(all_reflections)-int(missing_reflections) - except ValueError: - pass - return meassured_reflections - - def calculate_correlaton_between_intensities_in_mtzfiles(self,mtzin): - CC = '0.0' - errorMessage='' -# cmd = ( 'pointless hklin %s hklref %s << eof\n' %(mtzin,self.mtzfile)+ -# 'labref F=F\n' -# 'labin F=F\n' -# 'eof\n' ) - cmd = ( 'pointless hklin %s hklref %s << eof\n' %(mtzin,self.mtzfile)+ - 'labref I=IMEAN\n' - 'labin I=IMEAN\n' - 'eof\n' ) - - pointless=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE) - foundLine=False - for line in iter(pointless.stdout.readline,''): - if foundLine: - CC=line.split()[3] - break - if 'Alternative reindexing Lklhd CC' in line: - foundLine=True - if '**** Incompatible symmetries ****' in line: - errorMessage='**** Incompatible symmetries ****' - break - if 'Merged test dataset (HKLIN) has different Laue symmetry to reference set' in line: - errorMessage='%s has different Laue symmetry to %s' %(mtzin,self.mtzfile) - break - - return CC,errorMessage - - def get_all_values_as_dict(self): - mtz = { 'resolution_high': 'n/a', - 'unitcell': 'n/a', - 'spacegroup': 'n/a', - 'unitcell_volume': 'n/a', - 'bravais_lattice': 'n/a' } - a=0.0 - b=0.0 - c=0.0 - alpha_rad=0.0 - beta_rad=0.0 - gamma_rad=0.0 - resolution_line=1000000 - cell_line=1000000 - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' * Resolution Range :'): - resolution_line=n+2 - if n==resolution_line and len(line.split())==8: - mtz['resolution_high']=round(float(line.split()[5]),2) - if line.startswith(' * Cell Dimensions :'): - cell_line=n+2 - if n==cell_line and len(line.split())==6: - a= round(float(line.split()[0]),1) - b= round(float(line.split()[1]),1) - c= round(float(line.split()[2]),1) - alpha= round(float(line.split()[3]),1) - beta= round(float(line.split()[4]),1) - gamma= round(float(line.split()[5]),1) - mtz['unitcell']=str(a)+' '+str(b)+' '+str(c)+' '+ \ - str(alpha)+' '+str(beta)+' '+str(gamma) - alpha_rad=math.radians(alpha) - beta_rad= math.radians(beta) - gamma_rad=math.radians(gamma) - if line.startswith(' * Space group ='): - spg_number=int(line[line.rfind(')')-3:line.rfind(')')]) - mtz['bravais_lattice']=self.get_bravais_lattice_from_spg_number(spg_number) - mtz['spacegroup']=line[line.find("'")+1:line.rfind("'")] - if mtz['bravais_lattice']=='triclinic': - mtz['unitcell_volume']=a*b*c* \ - math.sqrt((1-math.cos(alpha_rad)**2-math.cos(beta_rad)**2-math.cos(gamma_rad)**2) \ - +2*(math.cos(alpha_rad)*math.cos(beta_rad)*math.cos(gamma_rad))) -# elif mtz['bravais_lattice']=='monoclinic': - elif 'monoclinic' in mtz['bravais_lattice']: - mtz['unitcell_volume']=round(a*b*c*math.sin(beta_rad),1) - elif mtz['bravais_lattice']=='orthorhombic' or mtz['bravais_lattice']=='tetragonal' or mtz['bravais_lattice']=='cubic': - mtz['unitcell_volume']=round(a*b*c,1) - elif mtz['bravais_lattice']=='hexagonal' or mtz['bravais_lattice']=='rhombohedral': - mtz['unitcell_volume']=round(a*b*c*(math.sin(math.radians(60))),1) - - return mtz - - def get_all_columns_as_dict(self): - column_dict = { 'F': [], - 'I': [], - 'SIG': [], - 'PHS': [], - 'FOM': [], - 'RFREE': [] } - startline=1000000 - mtzdmp=subprocess.Popen(['mtzdmp',self.mtzfile],stdout=subprocess.PIPE) - for n,line in enumerate(iter(mtzdmp.stdout.readline,'')): - if line.startswith(' Col Sort Min Max Num'): - startline=n+2 - if n >= startline and len(line.split()) > 10: - if line.split()[10] == 'F': - column_dict['F'].append(line.split()[11]) - if line.split()[10] == 'J': - column_dict['I'].append(line.split()[11]) - if line.split()[10] == 'Q': - column_dict['SIG'].append(line.split()[11]) - if line.split()[10] == 'I': - column_dict['RFREE'].append(line.split()[11]) - if line.split()[10] == 'P': - column_dict['PHS'].append(line.split()[11]) - if line.split()[10] == 'W': - column_dict['FOM'].append(line.split()[11]) - - return column_dict - - def get_all_columns_as_list(self): - column_list = self.iotbxMTZ.column_labels() - return column_list - -class queue: - - def jobs_in_queue(self): - jobs=[] - qstat=subprocess.Popen(['qstat -r'],stdout=subprocess.PIPE) - counter=0 - for n,line in enumerate(iter(qstat.stdout.readline,'')): - jobID='' - job_name='' - user_name='' - if getpass.getuser() in line: - counter +=1 - jobID=line.split()[0] - user_name=line.split()[3] - if "Full jobname:" in line: - job_name=line.split()[2] - jobs.append([counter,jobID,True,job_name,user_name]) - return jobs - - def remove_all_jobs_from_queue(self): - jobs_in_queue=self.jobs_in_queue() - if jobs_in_queue: - for job in jobs_in_queue: - os.system('qdel '+job[0]) - - - -class external_software: - - def __init__(self,xce_logfile): - - self.available_programs = {} - self.Logfile=XChemLog.updateLog(xce_logfile) - - def check(self): - - self.Logfile.insert('Searching for external software...') - - # default is False; user needs to explicitely set this - self.available_programs['qsub_remote']='' - - FNULL = open(os.devnull, 'w') - - try: -# subprocess.call(['qstat'], stdout=FNULL, stderr=subprocess.STDOUT) - p = subprocess.Popen('qstat', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) - status='found' - try: - for line in p.stdout: - if 'symbol lookup error:' in line or 'command not found' in line or 'error' in line: - self.available_programs['qsub']=False - self.available_programs['qsub_array']=False - status='not found' - array_status='not found' - except IOError: - self.available_programs['qsub']=False - self.available_programs['qsub_array']=False - status='not found' - array_status='not found' - - if status == 'found': - self.available_programs['qsub']=True -# if os.getcwd().startswith('/dls'): - if os.path.isdir('/dls'): - self.available_programs['qsub_array']=True - array_status='found' - else: - self.available_programs['qsub_array']=False - array_status='not found' - except OSError: - self.available_programs['qsub']=False - self.available_programs['qsub_array']=False - status='not found' - array_status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for qsub:', status)) -# print '{0:50} {1:10}'.format('-checking for qsub:', status) -# if os.getcwd().startswith('/dls'): - if os.path.isdir('/dls'): - self.Logfile.insert('{0:50} {1:10}'.format('checking for array qsub:', array_status)) - - try: - subprocess.call(['refmac5','end'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['refmac5']=True - status='found' - except OSError: - self.available_programs['refmac5']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for refmac5:', status)) - - try: - subprocess.call(['phenix.molprobity'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['phenix.molprobity']=True - status='found' - except OSError: - self.available_programs['phenix.molprobity']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for phenix.molprobity:', status)) - - try: - subprocess.call(['phenix.find_tls_groups'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['phenix.find_tls_groups']=True - status='found' - except OSError: - self.available_programs['phenix.find_tls_groups']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for phenix.find_tls_groups:', status)) - - try: - subprocess.call(['mmtbx.validate_ligands'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['mmtbx.validate_ligands']=True - status='found' - except OSError: - self.available_programs['mmtbx.validate_ligands']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for mmtbx.validate_ligands:', status)) - - try: - subprocess.call(['acedrg'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['acedrg']=True - shutil.rmtree('AcedrgOut_TMP') - status='found' - except OSError: - self.available_programs['acedrg']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for acedrg:', status)) - - try: - subprocess.call(['phenix.elbow'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['phenix.elbow']=True - status='found' - except OSError: - self.available_programs['phenix.elbow']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for phenix.elbow:', status)) - - try: - subprocess.call(['grade'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['grade']=True - status='found' - except OSError: - self.available_programs['grade']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for grade:', status)) - - try: - subprocess.call(['giant.create_occupancy_params'], stdout=FNULL, stderr=subprocess.STDOUT) - self.available_programs['giant.create_occupancy_params']=True - status='found' - except OSError: - self.available_programs['giant.create_occupancy_params']=False - status='not found' - self.Logfile.insert('{0:50} {1:10}'.format('checking for giant.create_occupancy_params:', status)) - - - return self.available_programs - - -class ParseFiles: - - def __init__(self,DataPath,xtalID): - # probably need to read in compoundID, because for custom projects, need to take newest pdb file - # that has not same root as compoundID - self.DataPath = DataPath - self.xtalID = xtalID - - if '' in DataPath: - self.newestPDB = max(glob.iglob(self.DataPath.replace('',xtalID)+'/*.pdb'), key=os.path.getctime) - else: - self.newestPDB = self.DataPath+'/'+self.xtalID+'/refine.pdb' - - def UpdateQualityIndicators(self): - - QualityIndicators = { 'R': '-', - 'RRfree': '-', - 'RRfreeColor': 'gray', - 'Resolution': 'n/a', - 'ResolutionColor': 'gray', - 'MolprobityScore': 'n/a', - 'MolprobityScoreColor': 'gray', - 'RamachandranOutliers': 'n/a', - 'RamachandranOutliersColor': 'gray', - 'RamachandranFavored': 'n/a', - 'RamachandranFavoredColor': 'gray', - 'LigandCCcolor': 'gray', - 'LigandCC': 'n/a', - 'rmsdBonds': 'n/a', - 'rmsdBondsColor': 'gray', - 'rmsdAngles': 'n/a', - 'rmsdAnglesColor': 'gray', - 'MatrixWeight': 'n/a' } - - # R, Rfree, Resolution - found = 0 - if os.path.isfile(self.newestPDB): - for line in open(self.newestPDB): - if line.startswith('REMARK 3 R VALUE (WORKING + TEST SET) :'): - QualityIndicators['R'] = line.split()[9] - if line.startswith('REMARK 3 FREE R VALUE :'): - QualityIndicators['RRfree'] = line.split()[6] - if float(line.split()[6]) < 0.3: QualityIndicators['RRfreeColor'] = 'green' - if float(line.split()[6]) >= 0.3 and float(line.split()[6]): QualityIndicators['RRfreeColor'] = 'orange' - if float(line.split()[6]) >= 0.4: QualityIndicators['RRfreeColor'] = 'red' - if line.startswith('REMARK 3 RESOLUTION RANGE HIGH (ANGSTROMS) :'): - QualityIndicators['Resolution'] = line.split()[7] - if float(line.split()[7]) < 2.4: QualityIndicators['ResolutionColor'] = 'green' - if 2.4 <= float(line.split()[7]) < 2.8: QualityIndicators['ResolutionColor'] = 'orange' - if float(line.split()[7]) >= 2.8: QualityIndicators['ResolutionColor'] = 'red' - if line.startswith('REMARK 3 BOND LENGTHS REFINED ATOMS (A):'): - QualityIndicators['rmsdBonds'] = line.split()[9] - if float(line.split()[9]) < 0.02: QualityIndicators['rmsdBondsColor'] = 'green' - if 0.02 <= float(line.split()[9]) < 0.03: QualityIndicators['rmsdBondsColor'] = 'orange' - if float(line.split()[9]) >= 0.03: QualityIndicators['rmsdBondsColor'] = 'red' - if line.startswith('REMARK 3 BOND ANGLES REFINED ATOMS (DEGREES):'): - QualityIndicators['rmsdAngles'] = line.split()[9] - if float(line.split()[9]) < 2.0: QualityIndicators['rmsdAnglesColor'] = 'green' - if 2.0 <= float(line.split()[9]) < 3.0: QualityIndicators['rmsdAnglesColor'] = 'orange' - if float(line.split()[9]) >= 3.0: QualityIndicators['rmsdAnglesColor'] = 'red' - - - # Molprobity - if os.path.isfile(self.DataPath+'/'+self.xtalID+'/validation_summary.txt'): - for line in open(self.DataPath+'/'+self.xtalID+'/validation_summary.txt'): -# if line.startswith(' Molprobity score ='): -# if line.lower().startswith(' molprobity score'): - if 'molprobity score' in line.lower(): - if len(line.split()) >= 4: - QualityIndicators['MolprobityScore'] = line.split()[3] - try: - if float(line.split()[3]) < 2: QualityIndicators['MolprobityScoreColor'] = 'green' - if 2 <= float(line.split()[3]) < 3: QualityIndicators['MolprobityScoreColor'] = 'orange' - if float(line.split()[3]) >= 3: QualityIndicators['MolprobityScoreColor'] = 'red' - except ValueError: - pass -# if line.lower().startswith(' ramachandran outliers ='): - if 'ramachandran outliers' in line.lower(): - if len(line.split()) >= 4: - QualityIndicators['RamachandranOutliers'] = line.split()[3] - try: - if float(line.split()[3]) < 0.3: QualityIndicators['RamachandranOutliersColor'] = 'green' - if 0.3 <= float(line.split()[3]) < 1: QualityIndicators['RamachandranOutliersColor'] = 'orange' - if float(line.split()[3]) >= 1: QualityIndicators['RamachandranOutliersColor'] = 'red' - except ValueError: - pass -# if line.startswith(' favored ='): - if 'favored' in line.lower(): - if len(line.split()) >= 3: - QualityIndicators['RamachandranFavored'] = line.split()[2] - try: - if float(line.split()[2]) < 90: QualityIndicators['RamachandranFavoredColor'] = 'red' - if 90 <= float(line.split()[2]) < 98: QualityIndicators['RamachandranFavoredColor'] = 'orange' - if float(line.split()[2]) >= 98: QualityIndicators['RamachandranFavoredColor'] = 'green' - except ValueError: - pass - - # LigandCC - if os.path.isfile(self.DataPath+'/'+self.xtalID+'/validate_ligands.txt'): - for line in open(self.DataPath+'/'+self.xtalID+'/validate_ligands.txt'): -# if line.startswith('| LIG'): - if 'LIG' in line: - QualityIndicators['LigandCC'] = line.split()[6] - if float(line.split()[6]) < 0.8: QualityIndicators['LigandCCcolor'] = 'red' - if 0.8 <= float(line.split()[6]) < 0.9: QualityIndicators['LigandCCcolor'] = 'orange' - if float(line.split()[6]) >= 0.9: QualityIndicators['LigandCCcolor'] = 'green' - - # Matrix Weight - temp = [] - found = 0 - if os.path.isdir(os.path.join(self.DataPath,self.xtalID)): - for item in glob.glob(os.path.join(self.DataPath,self.xtalID,'*')): - if item.startswith(os.path.join(self.DataPath,self.xtalID,'Refine_')): - temp.append(int(item[item.rfind('_')+1:])) - found = 1 - if found: - Serial = max(temp) - if os.path.isfile(os.path.join(self.DataPath,self.xtalID,'Refine_'+str(Serial),'refmac.log') ): - for line in open(os.path.join(self.DataPath,self.xtalID,'Refine_'+str(Serial),'refmac.log')): - if line.startswith(' Weight matrix') and len(line.split())==3: - QualityIndicators['MatrixWeight']=line.split()[2] - - return QualityIndicators - -class pdbtools(object): - - def __init__(self,pdb): - self.pdb = pdb - self.pdb_inp = iotbx.pdb.input(file_name=self.pdb) - self.hierarchy = self.pdb_inp.construct_hierarchy() - - - self.AminoAcids = ['ALA','ARG','ASN','ASP','CYS','GLU','GLN','GLY','HIS', - 'ILE','LEU','LYS','MET','PHE','PRO','SER','THR','TRP','TYR','VAL','CSO','HYP'] - self.Solvents = ['DMS','EDO','GOL','HOH'] - self.Ions = ['NA','MG','CL','K','SO4','PO4','CA'] - self.AAdict = {'ALA':'A','ARG':'R','ASN':'N','ASP':'D','CYS':'C','GLU':'E','GLN':'Q', - 'GLY':'G','HIS':'H','ILE':'I','LEU':'L','LYS':'K','MET':'M','PHE':'F', - 'PRO':'P','SER':'S','THR':'T','TRP':'W','TYR':'Y','VAL':'V'} - self.xce_ligands = ['LIG','DRG','FRS'] - - self.space_group_dict= { 'triclinic': [1], -# 'monoclinic': [3,4,5], - 'monoclinic_P': [3,4], - 'monoclinic_C': [5], - 'orthorhombic': [16,17,18,19,20,21,22,23,24], - 'tetragonal': [75,76,77,78,79,80,89,90,91,92,93,94,95,96,97,98], - 'hexagonal': [143,144,145,149,150,151,152,153,154,168,169,170, - 171,172,173,177,178,179,180,181,182], - 'rhombohedral': [146,155], - 'cubic': [195,196,197,198,199, - 207,208,209,210,211,212,213,214] } - - self.translate_spg_to_number_dict = { - 'p1': 1, 'p121': 3, 'p1211': 4, 'c2': 5, 'c121': 5, 'i2': 5, 'i121': 5, 'p222': 16, - 'p2122': 17, 'p2212': 17, 'p2221': 17, 'p21212': 18, 'p21221': 18, 'p22121': 18, - 'p212121': 19, 'c2221': 20, 'c222': 21, 'f222': 22, 'i222': 23, 'i212121': 24, - 'p4': 75, 'p41': 76, 'p42': 77, 'p43': 78, 'i4': 79, 'i41': 80, - 'p422': 89, 'p4212': 90, 'p4122': 91, 'p41212': 92, 'p4222': 93, 'p42212': 94, - 'p4322': 95, 'p43212': 96, 'i422': 97, 'i4122': 98, - 'p3': 143, 'p31': 144, 'p32': 145, 'p312': 149, 'p321': 150, 'p3112': 151, 'p3121': 152, - 'p3212': 153, 'p3221': 154, 'p6': 168, 'p61': 169, 'p65': 170, 'p62': 171, 'p64': 172, 'p63': 173, - 'p622': 177, 'p6122': 178, 'p6522': 179, 'p6222': 180, 'p6422': 181, 'p6322': 182, - 'r3': 146, 'h3': 146, 'r32': 155, 'h32': 155, - 'p23': 195, 'f23': 196, 'i23': 197, 'p213': 198, 'i213': 199, - 'p432': 207, 'p4232': 208, 'f432': 209, 'f4132': 210, 'i432': 211, 'p4332': 212, - 'p4132': 213, 'i4132': 214 - } - - - self.point_group_dict= { '1': [1], - '2': [3,4,5], - '222': [16,17,18,19,20,21,22,23,24], - '4': [75,76,77,78,79,80], - '422': [89,90,91,92,93,94,95,96,97,98], - '3': [143,144,145,146], - '32': [149,150,151,152,153,154,155], - '6': [168,169,170,171,172,173], - '622': [177,178,179,180,181,182], - '23': [195,196,197,198,199], - '432': [207,208,209,210,211,212,213,214] } - - self.nr_asu_in_unitcell_for_point_group = { '1': 1, - '2': 2, - '222': 4, - '4': 4, - '422': 8, - '3': 3, - '32': 6, - '6': 6, - '622': 12, - '23': 12, - '432': 24 } - - def amino_acids(self): - return self.AminoAcids - - def get_refinement_program(self): - program = 'unknown' - for remark in self.pdb_inp.remark_section(): - if 'PROGRAM' in remark: - if 'refmac' in remark.lower(): - program = 'REFMAC' - elif 'phenix' in remark.lower(): - program = 'PHENIX' - return program - - def get_residues_with_resname(self,resname): - ligands = [] - for model in self.hierarchy.models(): - for chain in model.chains(): - for conformer in chain.conformers(): - for residue in conformer.residues(): - if residue.resname == resname: - if [residue.resname, residue.resseq, chain.id] not in ligands: - ligands.append([residue.resname, residue.resseq, chain.id]) - return ligands - -# def get_centre_of_gravity_of_residue(self,resname_resseq_chain): - def get_centre_of_gravity_of_residue(self,resname_chain_resseq): - resname_x = resname_chain_resseq.split('-')[0] - chain_x = resname_chain_resseq.split('-')[1] - resseq_x = resname_chain_resseq.split('-')[2] - x = [] - y = [] - z = [] - for model in self.hierarchy.models(): - for chain in model.chains(): - for conformer in chain.conformers(): - for residue in conformer.residues(): - if residue.resname.replace(' ','') == resname_x and residue.resseq.replace(' ','') == resseq_x and chain.id.replace(' ','') == chain_x: - for atom in residue.atoms(): - x.append(atom.xyz[0]) - y.append(atom.xyz[1]) - z.append(atom.xyz[2]) - - if x != [] and y != [] and z != []: - x = ((max(x) - min(x)) / 2) + min(x) - y = ((max(y) - min(y)) / 2) + min(y) - z = ((max(z) - min(z)) / 2) + min(z) - - return x,y,z - - def save_residues_with_resname(self,outDir,resname): - ligands = self.get_residues_with_resname(resname) - ligList = [] - for l in ligands: - sel_cache = self.hierarchy.atom_selection_cache() - lig_sel = sel_cache.selection("(resname %s and resseq %s and chain %s)" % (l[0], l[1], l[2])) - hierarchy_lig = self.hierarchy.select(lig_sel) - -# ligName = (l[0] + '-' + l[1] + '-' + l[2] + '.pdb').replace(' ', '') - ligName = (l[0] + '-' + l[2] + '-' + l[1] + '.pdb').replace(' ', '') - ligList.append(ligName) - - f = open(os.path.join(outDir,ligName), "w") - f.write(hierarchy_lig.as_pdb_string(crystal_symmetry=self.pdb_inp.crystal_symmetry())) - f.close() - - return ligList - - def GetRefinementProgram(self): - program='' - for line in open(self.pdb): - if line.startswith('REMARK') and 'REFMAC' in line: - program='REFMAC' - break - if line.startswith('REMARK') and 'PHENIX' in line: - program='PHENIX' - break - if line.startswith('REMARK') and 'BUSTER' in line: - program='BUSTER' - break - - return program - - - def GetSequence(self): - chain = [] - Sequence='' - # need to count residue numbers in case of alternative conformations - ResiNum=[] - for line in open(self.pdb): - if line.startswith('ATOM') and line[17:20] in self.AminoAcids: - if line[21:22] not in chain: - chain.append(line[21:22]) - Sequence=Sequence+'\n>chain{0!s}.\n'.format(line[21:22]) - ResiNum=[] - if line[13:15]=='CA' and line[22:27] not in ResiNum: - Sequence=Sequence+self.AAdict[line[17:20]] - ResiNum.append(line[22:27]) - return Sequence - - - def GetProteinChains(self): - chain = [] - for line in open(self.pdb): - if line.startswith('ATOM'): - if line[17:20] in self.AminoAcids: - if line[21:22] not in chain: chain.append(line[21:22]) - return chain - - - def GetSymm(self): - unitcell = [] - a='' - b='' - c='' - alpha='' - beta='' - gamma='' - spg='' - for line in open(self.pdb): - if line.startswith('CRYST1'): - a=line.split()[1] - b=line.split()[2] - c=line.split()[3] - alpha=line.split()[4] - beta=line.split()[5] - gamma=line.split()[6] -# spg=line[55:len(line)-1] - spg=line[55:65] - return [a,b,c,alpha,beta,gamma,spg] - - def get_spg_from_pdb(self): - spg=self.GetSymm()[6] - return spg - - def get_spg_number_from_pdb(self): - spg=self.get_spg_from_pdb().replace(' ','').lower().replace('\n','').replace('\r','') - spg_number='0' - for key in self.translate_spg_to_number_dict: - if key==spg: - spg_number=str(self.translate_spg_to_number_dict[key]) - break - return spg_number - - def get_bravais_lattice_from_pdb(self): - bravais_lattice='' - spg_number=self.get_spg_number_from_pdb() - bravais_lattice=self.get_bravais_lattice_from_spg_number(spg_number) - return bravais_lattice - - def get_bravais_lattice_from_spg_number(self,number): - lattice='' - for bravaislattice in self.space_group_dict: - for spg_number in self.space_group_dict[bravaislattice]: - if str(spg_number)==str(number): - lattice=bravaislattice - return lattice - - def get_pointgroup_from_pdb(self): - pointgroup='' - spg_number=self.get_spg_number_from_pdb() - pointgroup=self.get_point_group_from_spg_number(spg_number) - return pointgroup - - def get_unit_cell_from_pdb(self): - symm=self.GetSymm() - unit_cell=symm[0:6] - return unit_cell - - def calc_unitcell_volume_from_pdb(self): - spg_number=self.get_spg_number_from_pdb() - lattice=self.get_bravais_lattice_from_spg_number(spg_number) - unitcell=self.get_unit_cell_from_pdb() - a=float(unitcell[0]) - b=float(unitcell[1]) - c=float(unitcell[2]) - alpha=math.radians(float(unitcell[3])) - beta= math.radians(float(unitcell[4])) - gamma=math.radians(float(unitcell[5])) - unitcell_volume=0 - if lattice=='triclinic': - unitcell_volume=a*b*c* \ - math.sqrt((1-math.cos(alpha)**2-math.cos(beta)**2-math.cos(gamma)**2) \ - +2*(math.cos(alpha)*math.cos(beta)*math.cos(gamma))) -# if lattice=='monoclinic': - if 'monoclinic' in lattice: - unitcell_volume=round(a*b*c*math.sin(beta),1) - if lattice=='orthorhombic' or lattice=='tetragonal' or lattice=='cubic': - unitcell_volume=round(a*b*c,1) - if lattice=='hexagonal' or lattice=='rhombohedral': - unitcell_volume=round(a*b*c*(math.sin(math.radians(60))),1) - return unitcell_volume - - - def MatthewsCoefficient(self,sequence): - chain=self.GetProteinChains() - symm=self.GetSymm() - nres=0 - for char in sequence: - if char != ' ': nres+=1 - - cmd = ( - '#!/bin/csh -f\n' - 'matthews_coef << eof\n' - ' cell %s\n' %(symm[0]+' '+symm[1]+' '+symm[2]+' '+symm[3]+' '+symm[4]+' '+symm[5])+ - ' symm {0!s}\n'.format(symm[6].replace(' ',''))+ - ' nres {0!s}\n'.format(nres)+ - ' auto\n' - ' end\n' - 'eof\n' - ) - Log = subprocess.check_output(cmd, shell=True) - MatthewsCoeff='n/a' - Solvent='n/a' - found=0 - for line in Log.split(os.linesep): - if found: - if int(line.split()[0]) == len(chain): - MatthewsCoeff=line.split()[1] - Solvent=line.split()[2] - break - if line.startswith('_______________'): - found=1 - - return [MatthewsCoeff,Solvent] - - - def find_ligands(self): - Ligands = [] - # need to count residue numbers in case of alternative conformations - ResiNum=[] - for line in open(self.pdb): - if (line.startswith('ATOM') or line.startswith('HETATM')) \ - and line[17:20].replace(' ','') not in self.AminoAcids+self.Solvents+self.Ions: - if [line[17:20],line[21:22],line[23:26]] not in Ligands: - Ligands.append([line[17:20],line[21:22],line[23:26]]) - return Ligands - - def save_ligands_to_pdb(self): - Ligands=self.find_ligands() - if not Ligands == []: - for n,item in enumerate(Ligands): - pdb='' - for line in open(self.pdb): - if line.startswith('CRYST'): - pdb+=line - if (line.startswith('ATOM') or line.startswith('HETATM')) and line[17:20]==item[0] and line[21:22]==item[1] and line[23:26]==item[2]: - pdb=pdb+line - f=open('ligand_{0!s}.pdb'.format(n),'w') - f.write(pdb) - f.close() - return Ligands - - def save_ligands_to_pdb_to_directory(self,outDir): - Ligands=self.find_ligands() - if not Ligands == []: - for n,item in enumerate(Ligands): - pdb='' - for line in open(self.pdb): - if line.startswith('CRYST'): - pdb+=line - if (line.startswith('ATOM') or line.startswith('HETATM')) and line[17:20]==item[0] and line[21:22]==item[1] and line[23:26]==item[2]: - pdb=pdb+line - f=open(os.path.join(outDir,'ligand_{0!s}.pdb'.format(n)),'w') - f.write(pdb) - f.close() - return Ligands - - - def save_all_ligands_to_pdb(self,outDir): - Ligands=self.find_ligands() - if not Ligands == []: - pdb='' - for line in open(self.pdb): - if line.startswith('CRYST'): - pdb+=line - for n,item in enumerate(Ligands): - for line in open(self.pdb): - if (line.startswith('ATOM') or line.startswith('HETATM')) and line[17:20]==item[0] and line[21:22]==item[1] and line[23:26]==item[2]: - pdb+=line - f=open(os.path.join(outDir,'all_ligands.pdb'),'w') - f.write(pdb) - f.close() - - def save_specific_ligands_to_pdb(self,resname,chainID,resseq,altLoc): - pdb='' - outDir=self.pdb[:self.pdb.rfind('/')] - for line in open(self.pdb): - if line.startswith('ATOM') or line.startswith('HETATM'): - resname_line=str(line[17:20]).replace(' ','') - chainID_line=str(line[21:23]).replace(' ','') - resseq_line=str(line[23:26]).replace(' ','') - altLoc_line=str(line[16:17]).replace(' ','') - if resname_line==str(resname) and chainID_line==str(chainID) and resseq_line==str(resseq) and altLoc_line==str(altLoc): - pdb=pdb+line - - if pdb != '': - f=open('{0!s}/ligand_{1!s}_{2!s}_{3!s}_{4!s}.pdb'.format(outDir, str(resname), str(chainID), str(resseq), str(altLoc)),'w') - f.write(pdb) - f.close() - - def find_xce_ligand_details(self): - Ligands = [] - for line in open(self.pdb): - if line.startswith('ATOM') or line.startswith('HETATM'): - resname=str(line[17:20]).replace(' ','') - if resname in self.xce_ligands: - chainID=str(line[21:23]).replace(' ','') - resseq=str(line[23:26]).replace(' ','') - altLoc=str(line[16:17]).replace(' ','') - if [resname,chainID,resseq,altLoc] not in Ligands: - Ligands.append([resname,chainID,resseq,altLoc]) - return Ligands - - def ligand_details_as_list(self): - Ligands = [] - for line in open(self.pdb): - if line.startswith('ATOM') or line.startswith('HETATM'): - resname=str(line[17:20]).replace(' ','') - if resname in self.xce_ligands: - chainID=str(line[21:23]).replace(' ','') - resseq=str(line[23:26]).replace(' ','') - altLoc=str(line[16:17]).replace(' ','') - occupancy=str(line[56:60]).replace(' ','') - if [resname,chainID,resseq,altLoc,occupancy] not in Ligands: - Ligands.append([resname,chainID,resseq,altLoc,occupancy]) - return Ligands - - def residue_details_as_list(self,pdbin): - residueList = [] - for line in open(pdbin): - if line.startswith('ATOM') or line.startswith('HETATM'): - resname=str(line[17:20]).replace(' ','') - chainID=str(line[21:23]).replace(' ','') - resseq=str(line[23:26]).replace(' ','') - altLoc=str(line[16:17]).replace(' ','') - occupancy=str(line[56:60]).replace(' ','') - if [resname,chainID,resseq,altLoc,occupancy] not in residueList: - residueList.append([resname,chainID,resseq,altLoc,occupancy]) - return residueList - - - def check_occupancies(self): - errorText='' - warningText='' - residueDict = {} - for line in open(self.pdb): - if line.startswith('ATOM') or line.startswith('HETATM'): - atomname=str(line[12:16]).replace(' ','') - resname=str(line[17:20]).replace(' ','') - chainID=str(line[21:22]).replace(' ','') - resseq=str(line[22:26]).replace(' ','') - altLoc=str(line[16:17]).replace(' ','') - occupancy=str(line[56:60]).replace(' ','') - if resname+'-'+chainID+'-'+resseq not in residueDict: - residueDict[resname+'-'+chainID+'-'+resseq] = [] - if altLoc == '': - altLoc='0' - residueDict[resname+'-'+chainID+'-'+resseq].append([altLoc,occupancy,atomname,resname,chainID,resseq]) - for item in residueDict: - altLocDict={} - for atom in residueDict[item]: - altLoc=atom[0] - occupancy=atom[1] - atomname=atom[2] - resname=atom[3] - chainID=atom[4] - resseq=atom[5] - if altLoc not in altLocDict: - altLocDict[altLoc]=[] - altLocDict[altLoc].append([occupancy,atomname,resname,chainID,resseq]) - if float(occupancy) > 1: - errorText+='ERROR: %s %s %s (%s) %s: occupancy is %s\n' %(chainID,resname,resseq,altLoc,atomname,occupancy) - occupancySumList=[] - for altLoc in altLocDict: - occupancySum=0.0 - nAtom=float(len(altLocDict[altLoc])) - for n,atom in enumerate(altLocDict[altLoc]): - occupancy=atom[0] - occupancySum+=float(occupancy) - atomname=atom[1] - resname=atom[2] - chainID=atom[3] - resseq=atom[4] - if n==0: - occStart=occupancy - else: - if occupancy != occStart: - warningText+='%s %s %s (%s) %s: occupancy differs for altLoc -> %s\n' %(chainID,resname,resseq,altLoc,atomname,occupancy) - occupancySumList.append(occupancySum/nAtom) - occAdd=0.0 - for entry in occupancySumList: - occAdd+=entry - if occAdd > 1: - errorText+='ERROR: '+item+' -> summarised occupanies of alternative conformations are > 1.0 ('+str(occupancySumList)+')\n' - - return errorText,warningText - - def get_xyz_coordinated_of_residue(self,chain,number): - X=0.0 - Y=0.0 - Z=0.0 - # pdb definition see: http://www.wwpdb.org/documentation/file-format-content/format33/sect9.html#ATOM - for line in open(self.pdb): - if (line.startswith('ATOM') or line.startswith('HETATM')) and line[21:22]==chain and line[22:26].replace(' ','')==str(number): - X=float(line[30:38]) - Y=float(line[38:46]) - Z=float(line[46:54]) - break - return X,Y,Z - - def get_center_of_gravity_of_residue_ish(self,chain,number): - print '-> chain:',chain - print '-> number:',number - X=0.0 - Y=0.0 - Z=0.0 - x_list=[] - y_list=[] - z_list=[] - # pdb definition see: http://www.wwpdb.org/documentation/file-format-content/format33/sect9.html#ATOM - for line in open(self.pdb): -# print line[21:22],line[22:26] - if (line.startswith('ATOM') or line.startswith('HETATM')) and line[21:22].replace(' ','')==chain.replace(' ','') and line[22:26].replace(' ','')==str(number).replace(' ',''): - X=float(line[30:38]) - x_list.append(X) - Y=float(line[38:46]) - y_list.append(Y) - Z=float(line[46:54]) - z_list.append(Z) - # 'ish' because it's not really the centre of gravity, but the the middle of the min/max of each x,y,z - X=((max(x_list)-min(x_list))/2)+min(x_list) - Y=((max(y_list)-min(y_list))/2)+min(y_list) - Z=((max(z_list)-min(z_list))/2)+min(z_list) - return X,Y,Z - - def get_center_of_gravity_of_molecule_ish(self): - X=0.0 - Y=0.0 - Z=0.0 - x_list=[] - y_list=[] - z_list=[] - # pdb definition see: http://www.wwpdb.org/documentation/file-format-content/format33/sect9.html#ATOM - for line in open(self.pdb): - if (line.startswith('ATOM') or line.startswith('HETATM')): - X=float(line[30:38]) - x_list.append(X) - Y=float(line[38:46]) - y_list.append(Y) - Z=float(line[46:54]) - z_list.append(Z) - # 'ish' because it's not really the centre of gravity, but the the middle of the min/max of each x,y,z - X=((max(x_list)-min(x_list))/2)+min(x_list) - Y=((max(y_list)-min(y_list))/2)+min(y_list) - Z=((max(z_list)-min(z_list))/2)+min(z_list) - return X,Y,Z - - def get_init_pdb_as_list(self): - return self.get_pdb_as_list(self.pdb) - - def get_pdb_as_list(self,pdbin): - pdb_list=[] - for line in open(pdbin): - if line.startswith('ATOM') or line.startswith('HETATM'): - atom_line=str(line[12:16]).replace(' ','') - resname_line=str(line[17:20]).replace(' ','') - chainID_line=str(line[21:23]).replace(' ','') - resseq_line=str(line[23:26]).replace(' ','') - altLoc_line=str(line[16:17]).replace(' ','') - pdb_list.append([atom_line,altLoc_line,resname_line,chainID_line,resseq_line]) - return pdb_list - - def ElementDict(self,resname,chainID,resseq,altLoc): - - ElementDict = { - 'C': 0, - 'N': 0, - 'O': 0, - 'P': 0, - 'S': 0, - 'BR': 0, - 'CL': 0, - 'I': 0, - 'F': 0 } - - for line in open(self.pdb): - if line.startswith('ATOM') or line.startswith('HETATM'): - atom_line=str(line[12:16]).replace(' ','') - resname_line=str(line[17:20]).replace(' ','') - chainID_line=str(line[21:23]).replace(' ','') - resseq_line=str(line[23:26]).replace(' ','') - altLoc_line=str(line[16:17]).replace(' ','') - element_line= str(line[66:78]).replace(' ','') - if resname_line==resname and chainID_line==chainID and resseq_line==resseq and altLoc_line==altLoc: - if element_line.upper() in ElementDict: - ElementDict[element_line.upper()] += 1 - - return ElementDict - - - def update_residue(self,resname_old,chainID_old,resseq_old,altLoc_old,occupancy_old,resname_new,chainID_new,resseq_new,altLoc_new,occupancy_new): - outPDB='' - for line in open(self.pdb): - if line.startswith('ATOM') or line.startswith('HETATM'): - atom_line= str(line[0:6]) - serial_line= str(line[6:11]) - atomName_line= str(line[11:16]) - altLoc_line= str(line[16:17]) - resname_line= str(line[17:20]) - chainID_line= str(line[20:23]) - resseq_line= str(line[23:26]) - insert_line= str(line[26:30]) - x_line= str(line[30:38]) - y_line= str(line[38:46]) - z_line= str(line[46:54]) - occupancy_line= str(line[54:60]) - Bfac_line= str(line[60:66]) - element_line= str(line[66:78]) - charge_line= str(line[78:80]) - if resname_line.replace(' ','')==resname_old and chainID_line.replace(' ','')==chainID_old and resseq_line.replace(' ','')==resseq_old and altLoc_line.replace(' ','')==altLoc_old: - - NewResname=resname_line.replace(resname_old,resname_new) - - NewChain = chainID_line.replace(chainID_old,chainID_new) - - if len(resseq_old) < len(resseq_new): - NewResseq=resseq_line.replace(resseq_old,' '*(len(resseq_old)-len(resseq_new))+resseq_new) - elif len(resseq_old) == len(resseq_new): - NewResseq=resseq_line.replace(resseq_old,resseq_new) - else: - NewResseq=resseq_line[len(resseq_new)-len(resseq_old):].replace(resseq_old,resseq_new) - - if altLoc_line == ' ': - NewAltloc=altLoc_line.replace(' ',altLoc_new) - else: - NewAltloc=altLoc_line.replace(altLoc_old,altLoc_new) - - NewOccupany=occupancy_line.replace(occupancy_old,occupancy_new) - - outPDB+=atom_line+serial_line+atomName_line+NewAltloc+NewResname+NewChain+NewResseq+insert_line+x_line+y_line+z_line+NewOccupany+Bfac_line+element_line+charge_line - else: - outPDB+=line - else: - outPDB+=line - - f=open(self.pdb,'w') - f.write(outPDB) - f.close() - - def merge_pdb_file(self,pdbin): - outPDB='' - - # only merge if residue with same resname, chain and resnumber not already in self.pdb!!! - residueListReference= self.residue_details_as_list(self.pdb) - residueListPDBin= self.residue_details_as_list(pdbin) - DuplicateResidue=False - for entry in residueListPDBin: - if entry in residueListReference: - print 'residue already exisits in '+self.pdb+':' - print str(entry) - DuplicateResidue=True - - if not DuplicateResidue: - for line in open(self.pdb): - if not line.startswith('END'): - outPDB+=line - - for line in open(pdbin): - if not line.startswith('END'): - outPDB+=line - - outPDB+='END\n' - - f=open(self.pdb,'w') - f.write(outPDB) - f.close() - else: - print 'cannot merge pdb files!' - - - def get_symmetry_operators(self): - symop = [] - spg_number=str(self.get_spg_number_from_pdb()) -# print 'spg',spg_number - foundSPG=False - if os.path.isfile(os.path.join(os.getenv('CCP4'),'lib','data','symop.lib')): -# print 'a',os.path.join(os.getenv('CCP4'),'lib','data','symop.lib') - for line in open(os.path.join(os.getenv('CCP4'),'lib','data','symop.lib')): -# print line.split()[0] - if foundSPG: - if line.startswith(' '): - tmp=line.replace('\n','') - symop.append(tmp.split(',')) - else: - break - if line.split()[0] == spg_number: - foundSPG=True - else: - print "CCP4 environmental variable is not set" - - return symop - - - def save_sym_equivalents(self): - unit_cell=self.get_unit_cell_from_pdb() - spg=self.get_spg_from_pdb() - symop=self.get_symmetry_operators() - outDir=self.pdb[:self.pdb.rfind('/')] - root=self.pdb[self.pdb.rfind('/')+1:self.pdb.rfind('.')] - outPDB=os.path.join(outDir,root+'_sym.pdb') - pdbset = ( '#!'+os.getenv('SHELL')+'\n' - 'pdbset xyzin %s xyzout %s << eof\n' %(self.pdb,outPDB)+ - 'cell {0!s}\n'.format((str(','.join(unit_cell))))+ - 'spacegroup {0!s}\n'.format(spg) ) - for op in symop: - pdbset+='SYMGEN '+','.join(op)+'\n' - pdbset+='eof\n' - os.system(pdbset) - - def save_sym_equivalents_of_ligands_in_pdb(self,pdbIN): - unit_cell=self.get_unit_cell_from_pdb() - spg=self.get_spg_from_pdb() - symop=self.get_symmetry_operators() - outDir=pdbIN[:pdbIN.rfind('/')] - root=pdbIN[pdbIN.rfind('/')+1:pdbIN.rfind('.')] - pdbset = ( '#!'+os.getenv('SHELL')+'\n' - 'pdbset xyzin %s xyzout %s/%s_0.pdb << eof\n' %(pdbIN,outDir,root)+ - 'cell {0!s}\n'.format((str(','.join(unit_cell))))+ - 'spacegroup {0!s}\n'.format(spg) ) - for op in symop: - pdbset+='SYMGEN '+','.join(op)+'\n' - pdbset+='eof\n' - os.system(pdbset) - return os.path.join(outDir,root+'_0.pdb') - - def save_sym_equivalents_of_ligands_in_pdb_as_one_file_per_ligand(self,pdbIN): - nres=0 - for line in open(pdbIN): - if line.startswith('ATOM') or line.startswith('HETATM'): - nres+=1 - print 'NRES',nres - unit_cell=self.get_unit_cell_from_pdb() - spg=self.get_spg_from_pdb() - symop=self.get_symmetry_operators() - outDir=pdbIN[:pdbIN.rfind('/')] - root=pdbIN[pdbIN.rfind('/')+1:pdbIN.rfind('.')] - pdbset = ( '#!'+os.getenv('SHELL')+'\n' - 'pdbset xyzin %s xyzout %s/out.pdb << eof 2> /dev/null\n' %(pdbIN,outDir)+ - 'cell {0!s}\n'.format((str(','.join(unit_cell))))+ - 'spacegroup {0!s}\n'.format(spg) ) - for op in symop: - pdbset+='SYMGEN '+','.join(op)+'\n' - pdbset+='eof\n' - os.system(pdbset) - - pdbList=[] - counter=0 - out='' - Cryst='' - n=0 - for line in open(os.path.join(outDir,'out.pdb')): - if line.startswith('CRYST'): - Cryst=line - if line.startswith('ATOM') or line.startswith('HETATM'): - if counter < nres-1: - if counter == 0: - out=Cryst - out+=line - counter+=1 - else: - out+=line - pdbList.append(os.path.join(outDir,root+'_'+str(n)+'.pdb')) - f=open(os.path.join(outDir,root+'_'+str(n)+'.pdb'),'w') - f.write(out) - f.close() - out='' - counter=0 - n+=1 - - return pdbList - - def save_surounding_unit_cells(self,pdbIN): - translations = [ - - [ 0, 1, 0 ], - [ 0, 1, 1 ], - [ 0, 0, 1 ], - [ 0, -1, 1 ], - [ 0, -1, 0 ], - [ 0, -1, -1 ], - [ 0, 0, -1 ], - [ 0, 1, -1 ], - - [ 1, 0, 0 ], - [ 1, 1, 0 ], - [ 1, 1, 1 ], - [ 1, 0, 1 ], - [ 1, -1, 1 ], - [ 1, -1, 0 ], - [ 1, -1, -1 ], - [ 1, 0, -1 ], - [ 1, 1, -1 ], - - [ -1, 0, 0 ], - [ -1, 1, 0 ], - [ -1, 1, 1 ], - [ -1, 0, 1 ], - [ -1, -1, 1 ], - [ -1, -1, 0 ], - [ -1, -1, -1 ], - [ -1, 0, -1 ], - [ -1, 1, -1 ], - - ] - - unit_cell=self.get_unit_cell_from_pdb() - spg=self.get_spg_from_pdb() - outDir=pdbIN[:pdbIN.rfind('/')] - root=pdbIN[pdbIN.rfind('/')+1:pdbIN.rfind('.')] - - for n,shift in enumerate(translations): - pdbset = ( '#!'+os.getenv('SHELL')+'\n' - 'pdbset xyzin %s/%s.pdb xyzout %s/%s_%s.pdb << eof 2> /dev/null\n' %(outDir,root,outDir,root,str(n+1))+ - 'cell {0!s}\n'.format((str(','.join(unit_cell))))+ - 'spacegroup {0!s}\n'.format(spg)+ - 'shift fractional {0!s}\n'.format(str(shift).replace('[','').replace(']',''))+ - 'eof\n' ) - print 'pdinin',pdbIN - print 'outdir',outDir - print 'root',root - print pdbset - os.system(pdbset) - - - -class logtools: - - def __init__(self,logfile): - self.logfile=logfile - - def phenix_molprobity(self): - QualityIndicators = { 'MolprobityScore': 'n/a', - 'MolprobityScoreColor': 'gray', - 'RamachandranOutliers': 'n/a', - 'RamachandranOutliersColor': 'gray', - 'RamachandranFavored': 'n/a', - 'RamachandranFavoredColor': 'gray' } - - - # Molprobity = validation_summary.txt - if os.path.isfile(self.logfile): - for line in open(self.logfile): - if 'molprobity score' in line.lower(): - if len(line.split()) >= 4: - QualityIndicators['MolprobityScore'] = line.split()[3] - try: - if float(line.split()[3]) < 2: QualityIndicators['MolprobityScoreColor'] = 'green' - if 2 <= float(line.split()[3]) < 3: QualityIndicators['MolprobityScoreColor'] = 'orange' - if float(line.split()[3]) >= 3: QualityIndicators['MolprobityScoreColor'] = 'red' - except ValueError: - pass -# if line.lower().startswith(' ramachandran outliers ='): - if 'ramachandran outliers' in line.lower(): - if len(line.split()) >= 4: - QualityIndicators['RamachandranOutliers'] = line.split()[3] - try: - if float(line.split()[3]) < 0.3: QualityIndicators['RamachandranOutliersColor'] = 'green' - if 0.3 <= float(line.split()[3]) < 1: QualityIndicators['RamachandranOutliersColor'] = 'orange' - if float(line.split()[3]) >= 1: QualityIndicators['RamachandranOutliersColor'] = 'red' - except ValueError: - pass -# if line.startswith(' favored ='): - if 'favored' in line.lower(): - if len(line.split()) == 4: - QualityIndicators['RamachandranFavored'] = line.split()[2] - try: - if float(line.split()[2]) < 90: QualityIndicators['RamachandranFavoredColor'] = 'red' - if 90 <= float(line.split()[2]) < 98: QualityIndicators['RamachandranFavoredColor'] = 'orange' - if float(line.split()[2]) >= 98: QualityIndicators['RamachandranFavoredColor'] = 'green' - except ValueError: - pass - - return QualityIndicators - - - def refmac_log(self): - QualityIndicators = { 'MatrixWeight': 'n/a' } - - # Matrix Weight - if os.path.isfile(self.logfile): - for line in open(self.logfile): - if line.startswith(' Weight matrix') and len(line.split())==3: - QualityIndicators['MatrixWeight']=line.split()[2] - - return QualityIndicators - - - -class reference: - - def __init__(self,sample_mtz,reference_file_list): - self.sample_mtz=sample_mtz - self.reference_file_list=reference_file_list -# print reference_file_list - - def find_suitable_reference(self,allowed_unitcell_difference_percent): - found_suitable_reference=False - unitcell_reference='n/a' - reference='' - spg_reference='n/a' - unitcell_difference='n/a' - resolution_high='n/a' - spg_autoproc='n/a' - unitcell_autoproc='n/a' - if os.path.isfile(self.sample_mtz): - mtz_autoproc=mtztools(self.sample_mtz).get_all_values_as_dict() - resolution_high=mtz_autoproc['resolution_high'] - spg_autoproc=mtz_autoproc['spacegroup'] - unitcell_autoproc=mtz_autoproc['unitcell'] - lattice_autoproc=mtz_autoproc['bravais_lattice'] - unitcell_volume_autoproc=mtz_autoproc['unitcell_volume'] - # check which reference file is most similar - for o,reference_file in enumerate(self.reference_file_list): -# print reference_file - try: - if not reference_file[4]==0: - unitcell_difference=round((math.fabs(reference_file[4]-unitcell_volume_autoproc)/reference_file[4])*100,1) - # reference file is accepted when different in unitcell volume < 5% - # and both files have the same lattice type - if unitcell_difference < allowed_unitcell_difference_percent and lattice_autoproc==reference_file[3]: - spg_reference=reference_file[1] - unitcell_reference=reference_file[2] - reference=reference_file[0] - found_suitable_reference=True - break - except IndexError: - pass - return (spg_reference,unitcell_reference,reference,found_suitable_reference, - resolution_high,spg_autoproc,unitcell_autoproc,unitcell_difference) - - -class misc: - - def calculate_distance_between_coordinates(self,x1,y1,z1,x2,y2,z2): -# print '==> XCE: calculating distance between two coordinates' - distance=0.0 - distance=math.sqrt(math.pow(float(x1)-float(x2),2)+math.pow(float(y1)-float(y2),2)+math.pow(float(z1)-float(z2),2)) - return distance - -class smilestools(object): - def __init__(self,smiles): - self.smiles=smiles - - def ElementDict(self): - ElementDict = { - 'C': 0, - 'N': 0, - 'O': 0, - 'P': 0, - 'S': 0, - 'BR': 0, - 'CL': 0, - 'I': 0, - 'F': 0 } - - m = Chem.MolFromSmiles(self.smiles) - for atom in m.GetAtoms(): - if str(atom.GetSymbol()).upper() in ElementDict: - ElementDict[str(atom.GetSymbol()).upper()] += 1 - - return ElementDict - -class maptools(object): - def __init__(self,map): - - self.translate_spg_to_number_dict = { - 'p1': 1, 'p2': 3, 'p121': 4, 'c2': 5, 'c121': 5, 'p222': 16, - 'p2122': 17, 'p2212': 17, 'p2221': 17, 'p21212': 18, 'p21221': 18, 'p22121': 18, - 'p212121': 19, 'c2221': 20, 'c222': 21, 'f222': 22, 'i222': 23, 'i212121': 24, - 'p4': 75, 'p41': 76, 'p42': 77, 'p43': 78, 'i4': 79, 'i41': 80, - 'p422': 89, 'p4212': 90, 'p4122': 91, 'p41212': 92, 'p4222': 93, 'p42212': 94, - 'p4322': 95, 'p43212': 96, 'i422': 97, 'i4122': 98, - 'p3': 143, 'p31': 144, 'p32': 145, 'p312': 149, 'p321': 150, 'p3112': 151, 'p3121': 152, - 'p3212': 153, 'p3221': 154, 'p6': 168, 'p61': 169, 'p65': 170, 'p62': 171, 'p64': 172, 'p63': 173, - 'p622': 177, 'p6122': 178, 'p6522': 179, 'p6222': 180, 'p6422': 181, 'p6322': 182, - 'r3': 146, 'h3': 146, 'r32': 155, 'h32': 155, - 'p23': 195, 'f23': 196, 'i23': 197, 'p213': 198, 'i213': 199, - 'p432': 207, 'p4232': 208, 'f432': 209, 'f4132': 210, 'i432': 211, 'p4332': 212, - 'p4132': 213, 'i4132': 214 } - - self.map=map - cmd = ( 'mapdump mapin {0!s} << eof\n'.format(self.map)+ - 'end\n' - 'eof' ) - mapdump=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE) - self.grid_sampling=[0,0,0] - self.cell_dimensions=[] - self.space_group_number=0 - for line in iter(mapdump.stdout.readline,''): - if 'Grid sampling on x, y, z' in line: - if len(line.split()) == 10: - self.grid_sampling=[line.split()[7],line.split()[8],line.split()[9]] - if 'Cell dimensions' in line: - if len(line.split()) == 9: - self.cell_dimensions=[line.split()[3],line.split()[4],line.split()[5],line.split()[6],line.split()[7],line.split()[8]] - if 'Space-group' in line: - if len(line.split()) == 3: - self.space_group_number=line.split()[2] - - def grid_sampling(self): - return self.grid_sampling - - def cell_dimensions(self): - return self.cell_dimensions - - def space_group_number(self): - return self.space_group_number - - def space_group(self): - space_group='' - space_group_number=self.space_group_number - for spg in self.translate_spg_to_number_dict: - if str(self.translate_spg_to_number_dict[spg]) == str(space_group_number): - space_group=str(spg) - return space_group - diff --git a/lib/coot_utils_XChem.py b/lib/coot_utils_XChem.py deleted file mode 100755 index 71ef6a78..00000000 --- a/lib/coot_utils_XChem.py +++ /dev/null @@ -1,3846 +0,0 @@ -# coot-utils.py -# adapted from coot-utils.scm -# -# Copyright 2004, 2005, 2006, 2007 by Bernhard Lohkamp -# Copyright 2008, 2009 by Bernhard Lohkamp, The University of York -# Copyright 2000 by Paul Emsley -# Copyright 2004, 2005, 2006, 2007 by Paul Emsley, The University of York -# -# Copyright (C) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import sys -sys.path.append('/usr/local/coot/current/lib/python2.7/site-packages') -import coot - -import re, string, os - -# 3D annotations - a bit of a hack currently -global annotations -annotations = [] - -# used in Extensions -> Representation -> Ball & Stick -global default_ball_and_stick_selection -default_ball_and_stick_selection = "//A/1-2" - -# for mingw debug -global have_mingw -have_mingw = False -if os.getenv("MSYSTEM"): - have_mingw = True - - -global user_defined_alert_smarts -# example: user_defined_alert_smarts = [['C', 'my-user-defined alert for carbon']] -user_defined_alert_smarts = [] - - - -# not sure if the implementation of the macros will work - -# 'Macro' to tidy up a a setup of functions to be run with no backup -# for a particular molecule. -# -# funcs is a normal set of functions (not a thunk), here i.e. a list of -# functions with function as a list with func name and args, -# e.g.: [centre_of_mass, 0], [func_name, arg1, arg2,...],... -# -def with_no_backups(imol, *funcs): - - b_state = backup_state(imol) - turn_off_backup(imol) - for f in funcs: - func = f[0] - args = f[1:len(f)] - #print "BL DEBUG:: func %s and args %s" %(func, args) - func(*args) - if backup_mode == 1: - turn_on_backup(imol) - - -# 'Macro' to tidy up a set of functions to be run with automatic -# accepting of the refinement -# returns the result of last function run... -# -# funcs is a normal set of functions (not a thunk), here i.e. a list of -# functions with function as a list with func name and args, -# e.g.: [centre_of_mass, 0], [func_name, arg1, arg2,...],... -# -def with_auto_accept(*funcs): - - replace_state = refinement_immediate_replacement_state() - set_refinement_immediate_replacement(1) - for f in funcs: - func = f[0] - args = f[1:len(f)] - #print "BL DEBUG:: func %s and args %s" %(func, args) - ret = func(*args) - accept_regularizement() - - if (replace_state == 0): - set_refinement_immediate_replacement(0) - - return ret # returns result of last functions!!!! - -# 'Macro' to run funcs on an active atom -# funcs is function, active_atom specifiers and extra args -# func, args, "aa_imol", "aa_chain_id", ..., args -# or list thereof -# [[func1, extra_arg1, ..., "aa_imol", "aa_chain_id",..., extra_arg2, extra arg3, ..], [func2,...]] -# returns what? The value from the last function evaluated -# -def using_active_atom(*funcs): - - from types import ListType - active_atom = active_residue() - if (not active_atom): - add_status_bar_text("No residue found") - else: - - def arg_to_append(item): - aa_dict = {"aa_imol": active_atom[0], - "aa_chain_id": active_atom[1], - "aa_res_no": active_atom[2], - "aa_ins_code": active_atom[3], - "aa_atom_name": active_atom[4], - "aa_alt_conf": active_atom[5]} - - if isinstance(item, list): - arg_ls = [] - for ele in item: - arg_ls.append(arg_to_append(ele)) - return arg_ls - else: - if aa_dict.has_key(item): - return aa_dict[item] - else: - return item - - if (len(funcs) == 1): - # we have a list of functions - # so use - ls_funcs = funcs[0] - elif (type(funcs[0]) is ListType): - # we have a range of lists - # use as is - ls_funcs = funcs - else: - # we have a single function with args - # make into list - ls_funcs = [funcs] - - for ele in ls_funcs: - func = ele[0] - func_args = ele[1:] - args = [] - for arg in func_args: - ins = arg_to_append(arg) - args.append(ins) - ret = func(*args) - return ret - -# here some truely pythonic version of the macros. Should replace -# them in usage too: - -# Pythonic 'Macro' to tidy up a a setup of functions to be run with no backup -# for a particular molecule. -# -# use with 'with', e.g.: -# -# > with NoBackups(imol=0): -# refine_zone(imol, "A", 43, 45, "") -# accept_regularizement() -# -class NoBackups: - """'Macro' to tidy up a a setup of functions to be run with no backup - for a particular molecule. - - use with 'with', e.g.: - - > with WithNoBackups(imol=0): - refine_zone(imol, "A", 43, 45, "") - accept_regularizement() - """ - - def __init__(self, imol): - self.imol = imol - def __enter__(self): - self.b_state = backup_state(self.imol) - turn_off_backup(self.imol) - def __exit__(self, type, value, traceback): - if (self.b_state == 1): - turn_on_backup(self.imol) - -# Pythonic 'Macro' to tidy up a set of functions to be run with automatic -# accepting of the refinement. -# -# use with 'with', e.g.: -# -# >with AutoAccept(): -# refine_zone(0, "A", 43, 45, "") -# -class AutoAccept: - """ - Pythonic 'Macro' to tidy up a set of functions to be run with automatic - accepting of the refinement. - - use with 'with', e.g.: - - > with AutoAccept(): - refine_zone(0, "A", 43, 45, "") - - """ - - def __init__(self): - self.replace_state = -1 - pass - def __enter__(self): - self.replace_state = refinement_immediate_replacement_state() - set_refinement_immediate_replacement(1) - def __exit__(self, type, value, traceback): - accept_regularizement() - if (self.replace_state == 0): - set_refinement_immediate_replacement(0) - - -class UsingActiveAtom: - """ - Run functions on the active atom. - - use with 'with', e.g.: - - > with UsingActiveAtom() as [aa_imol, aa_chain_id, aa_res_no, aa_ins_code, aa_atom_name, aa_alt_conf]: - refine_zone(aa_imol, aa_chain_id, aa_res_no-2, aa_res_no+2, aa_ins_code) - """ - - def __init__(self): - self.no_residue = False - pass - def __enter__(self): - self.active_atom = active_residue() - if (not self.active_atom): - add_status_bar_text("No (active) residue found") - self.no_residue = True - #self.__exit__(None, "dummy", None) - else: - imol = self.active_atom[0] - chain_id = self.active_atom[1] - res_no = self.active_atom[2] - ins_code = self.active_atom[3] - atom_name = self.active_atom[4] - alt_conf = self.active_atom[5] - return [imol, chain_id, res_no, ins_code, atom_name, alt_conf] - def __exit__(self, type, value, traceback): - if (self.no_residue): - # internal calling of exit, ignore errors - return True - pass - - -# Pythonize function: return a python boolean. -# -def molecule_has_hydrogens(imol): - return (molecule_has_hydrogens_raw(imol) == 1) - -def add_hydrogens_using_refmac(imol): - out_file_name = os.path.join("coot-refmac", - molecule_name_stub(imol, 0) + '-needs-H.pdb') - in_file_name = os.path.join("coot-refmac", - molecule_name_stub(imol, 0) + '-with-H.pdb') - make_directory_maybe('coot-refmac') - write_pdb_file(imol, out_file_name) - return add_hydrogens_using_refmac_inner(imol, in_file_name, out_file_name) - - -def add_hydrogens_to_chain_using_refmac(imol, chain_id): - out_file_name = os.path.join("coot-refmac", - molecule_name_stub(imol, 0) + '-chain-' + chain_id + '-needs-H.pdb') - in_file_name = os.path.join("coot-refmac", - molecule_name_stub(imol, 0) + '-chain-' + chain_id + '-with-H.pdb') - make_directory_maybe('coot-refmac') - write_chain_to_pdb_file(imol, chain_id, out_file_name) - return add_hydrogens_using_refmac_inner(imol, in_file_name, out_file_name) - - -def add_hydrogens_using_refmac_inner(imol, in_file_name, out_file_name): - - status = popen_command("refmac5", - ['XYZIN', out_file_name, 'XYZOUT', in_file_name], - ['MAKE HOUT YES'], - 'refmac-H-addition.log', 0) - try: - if (status == 0): - # all good - return add_hydrogens_from_file(imol, in_file_name) - except: - return False - - - -# set this to a function accepting two argument (the molecule number -# and the manipulation mode) and it will be run after a model -# manipulation. -# e.g. -# def post_manipulation_script(imol, mode): -# ... continue below -# -# The manipulation mode will be one of (MOVINGATOMS), (DELETED) or -# (MUTATED) and these can be tested with "=". -# -# e.g. -# -# if (mode == DELETED): -# display/print "Something was deleted" -# -post_manipulation_script = False - -# return a boolean -# -def pre_release_qm(): - return "-pre" in coot_version() - - -# return a list of molecule numbers (closed and open) -# The elements of the returned list need to be tested against -# is_valid_model_molecule_qm -# -def molecule_number_list(): - ret = [] - for mol_no in range(coot.graphics_n_molecules()): - if (valid_map_molecule_qm(mol_no) or - valid_model_molecule_qm(mol_no)): - ret.append(mol_no) - return ret - -def model_molecule_number_list(): - return filter(valid_model_molecule_qm, molecule_number_list()) - -# Test for prefix-dir (1) being a string (2) existing (3) being a -# directory (4-6) modifiable by user (ie. u+rwx). prefix_dir must be a -# string. -# -# Return True or False. -# -def directory_is_modifiable_qm(prefix_dir): - from types import StringType - ret = False - # check string: - ret = type(prefix_dir) is StringType - if ret: - # check existence: - ret = os.access(prefix_dir, os.F_OK) - if ret: - # check dir: - ret = os.path.isdir(prefix_dir) - if ret: - # check readability - ret = os.access(prefix_dir, os.R_OK) - if ret: - # check writability - ret = os.access(prefix_dir, os.W_OK) - if ret: - # check executability (needed?!) - ret = os.access(prefix_dir, os.X_OK) - return ret - -# return an absolute file-name for file-name or False -# -# def absolutify(file_name) - exists in python as os.path.abspath use that!! - -# Find the most recently created file from the given glob and dir -# -# return False on no-such-file -# -def most_recently_created_file(glob_str, dir): - - import glob, time - - patt = os.path.join(dir, glob_str) - files = glob.glob(patt) - - latest_file = False - latest_mtime = 0 - - for file_ in files: - this_mtime = os.path.getmtime(file_) - if this_mtime > latest_mtime: - latest_file = file_ - latest_mtime = this_mtime - - return latest_file - - -# Convert a residue_spec to an mmdb atom selection string. -# FIXME:: to be tested -# -def residue_spec2atom_selection_string(centre_residue_spec): - ret = "//" + centre_residue_spec[0] + \ - "/" + str(centre_residue_spec[1]) - return ret - -def residue_atom2atom_name(ra): - if not isinstance(ra, list): - return False - else: - return ra[0][0] - -def residue_atom2alt_conf(ra): - if not isinstance(ra, list): - return False - else: - return ra[0][1] - -def residue_spec2chain_id(rs): - if not isinstance(rs, list): - return False - else: - if (len(rs) == 3): - return rs[0] - else: - if (len(rs) == 4): - return rs[1] - else: - return False - -def residue_spec2res_no(rs): - if not isinstance(rs, list): - return False - else: - if (len(rs) == 3): - return rs[1] - else: - if (len(rs) == 4): - return rs[2] - return False - -def residue_spec2ins_code(rs): - if not isinstance(rs, list): - return False - else: - if (len(rs) == 3): - return rs[2] - else: - if (len(rs) == 4): - return rs[3] - return False - -def atom_spec2imol(atom_spec): - import types - if not (isinstance(atom_spec, types.ListType)): - return False - else: - if (len(atom_spec) == 6): - return atom_spec[0] - if (len(atom_spec) == 7): - return atom_spec[1] - return False - -def residue_spec2residue_name(imol, spec): - return residue_name(imol, - spec[1], - spec[2], - spec[3]) - -# Return a list of molecules that are maps -# -def map_molecule_list(): - - map_list = [] - for i in range(graphics_n_molecules()): - if is_valid_map_molecule(i): - map_list.append(i) - return map_list - -# Return a list of molecules that are (coordinate) models -# -def model_molecule_list(): - - model_list = [] - for i in range(graphics_n_molecules()): - if is_valid_model_molecule(i): - model_list.append(i) - return model_list - -# Return True(False) if @var{imol} is (isn't) a shelx molecule. -# -def shelx_molecule_qm(imol): - if (is_shelx_molecule(imol) == 1): - return True - else: - return False - -# Set the virtual trackball behaviour. -# -# trackball @var{type} is a string: either 'flat' or 'spherical-surface' -# -def set_virtual_trackball_type(type): - if (type == "flat"): - vt_surface(1) - elif (type == "spherical-surface"): - vt_surface(0) - else: - print "virtual trackball type",type,"not understood" - -# Is ls a list of strings? Return True or False -# -def list_of_strings_qm(ls): - import types - not_str =0 - if type(ls) is not ListType: - return False - else: - for item in ls: - if isinstance(item,types.StringTypes): pass - else: not_str += 1 - if not_str == 0: - return True - else: - return False - -# string concat with spaces, @var{ls} must be a list of strings. -# -def string_append_with_spaces(ls): - - import string - if ls: - return string.join(ls) - else: - return [""] - -# The screen centre. -# -# return the rotation centre as a 3 membered list of numbers -# is python list [...] !!! -# -def rotation_centre(): - return [coot.rotation_centre_position(0), - coot.rotation_centre_position(1), - coot.rotation_centre_position(2)] - -# this is actually not essentail since python has these funtion(s) -def number_list(a,b): - result = [] - if a == b: - result.append(a) - return result - elif a > b : return result - else : - while a <=b : - result.append(a) - a = a + 1 - return result - -def file_n_lines(file_name): - if not os.path.isfile(file_name): - return False - else: - fin = open(file_name, 'r') - n_lines = sum(1 for line in fin) - fin.close() - return n_lines - -# backport, so that we can replace once move to Python 2.7 is done -def check_output(*popenargs, **kwargs): - r"""Run command with arguments and return its output as a byte string. - -Backported from Python 2.7 as it's implemented as pure python on stdlib. - ->>> check_output(['/usr/bin/python', '--version']) -Python 2.6.2 -""" - - import subprocess - process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - error = subprocess.CalledProcessError(retcode, cmd) - error.output = output - raise error - return output - -# returns false of there is a problem running cmd -# -def shell_command_to_string(cmd): - - import subprocess - import sys - - major, minor, micro, releaselevel, serial = sys.version_info - - if (major >= 2 and minor >= 7): - try: - ret = subprocess.check_output(cmd.split()) - except: - ret = False - else: - try: - ret = check_output(cmd) - except: - ret = False - return ret - -# Return True or False -# adapted from find_exe -# this finds absolute file names too -# -def command_in_path_qm(cmd, only_extension_here=None, - add_extensions_here=None): - - if add_extensions_here is None: - add_extensions_here = [] - exe_path = find_exe(cmd, "PATH", no_disk_search=True, - screen_info=False, - only_extension=only_extension_here, - add_extensions=add_extensions_here) - - if exe_path: - return True - else: - return False - - - -def command_in_path_qm_old_version(cmd, only_extension="", add_extensions=None): - # test for command (see goosh-command-with-file-input description) - # - if add_extensions is None: - add_extensions = [] - import os, string - - # we shall check for full path names first - if (os.path.isfile(cmd)): - return True - else: - extensions = [] - cmd_noext = cmd - # some windows magic - if (os.name == 'nt'): - file_ext = file_name_extension(cmd) - cmd_noext = strip_extension(cmd) - if (file_ext): - extensions = [file_ext] - else: - tmp_ext = os.environ["PATHEXT"].split(os.pathsep) - # list of extensions (no dot) only - extensions = map(lambda ext: ext[1:], tmp_ext) - - if only_extension: - extensions = [only_extension] - if add_extensions: - extensions += add_extensions - - program_names = [cmd_noext] - if extensions: - program_names += map(lambda ext: cmd_noext + "." + ext, - extensions) - - try: - primary_path = os.environ["PATH"] - for cmd_name in program_names: - for path in string.split(primary_path, os.pathsep): - program_exe = os.path.join(path, cmd_name) - # print "BL DEBUG:: program_exe is", program_exe - if (os.path.isfile(program_exe)): - return True - return False - except: - print "BL WARNING:: couldnt open $PATH" # this shouldnt happen - return False - - -global gtk_thread_return_value -gtk_thread_return_value = None -# Where cmd is e.g. "refmac" -# args is ["HKLIN","thing.mtz"] -# data_list is ["HEAD","END"] -# log_file_name is "refmac.log" -# screen_flag True/False to display or not in shell window -# -# Return the exist status e.g. 0 or 1. Or False if cmd not found. -# -# uses os.popen if python version < 2.4 otherwise subprocess -# -def popen_command(cmd, args, data_list, log_file, screen_flag=False): - - import sys, string, os - - major, minor, micro, releaselevel, serial = sys.version_info - - if (os.path.isfile(cmd)): - cmd_execfile = cmd - else: - if not(command_in_path_qm(cmd)): - print "command ", cmd, " not found in $PATH!" - print "BL INFO:: Maybe we'll find it somewhere else later..." - cmd_execfile = find_exe(cmd, "CCP4_BIN", "PATH") - - if (cmd_execfile): - # minor = 2 - if (major >= 2 and minor >=4): - # subprocess - import subprocess - log = open(log_file, 'w') - cmd_args = [cmd_execfile] + args - if (screen_flag): - process = subprocess.Popen(cmd_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - else: - process = subprocess.Popen(cmd_args, stdin=subprocess.PIPE, stdout=log) - - for data in data_list: - process.stdin.write(data + "\n") - process.stdin.close() - if (screen_flag): - for line in process.stdout: - print "#", line.rstrip(" \n") # remove trailing whitespace - log.write(line) - process.wait() - log.close() - - return process.returncode - - else: - # popen (old) - data_list_file = "data_list_file_tmp.txt" - - # make args string - args_string = string.join(args) - - # write tmp input file - input = file (data_list_file,'w') - for data in data_list: - input.write(data + '\n') - input.close() - - # print "BL DEBUG:: popen command is", cmd_execfile + " " + args_string + " < " + data_list_file + " > " + log_file - status = os.popen(cmd_execfile + " " + args_string + " < " + data_list_file + " > " + log_file, 'r') - cmd_finished = status.close() - if (cmd_finished is not None): - print "running command ", cmd, " failed!" - return 1 - else: - # print "cmd ", cmd ," seems to have run ok!" - # log_file_size = os.stat(log_file)[stat.ST_SIZE] - return 0 - os.remove(data_list_file) - else: - print "WARNING:: could not find {0!s}, so not running".format(cmd) - return False - -# example usage: -# popen_command("mtzdump",["HKLIN","a.mtz"],["HEAD","END"],"test.log",0) - -# Crude test to see of 2 floats are the same (more or less). -# Used in a unit test after setting the atom position. -# -def close_float_qm(x1, x2): - - return (abs(x1 - x2) < 0.001) - -# "a.b.res" -> "a.b" -# file_name_sans_extension -# -def strip_extension(s): - import os - head, tail = os.path.splitext(s) - return head - -# What is the extension of file_name? -# -# "a.pdb" -> "pdb" -# "" -> "" -# -def file_name_extension(file_name): - - import os, string - root, ext = os.path.splitext(file_name) - if ext: - ext = string.lstrip(ext,'.') - return ext - else: - return "" - -# e.g. "a.pdb" -> "a-tmp.pdb" -# -def add_tmp_extension_to(file_name): - - import types - if isinstance(file_name,types.StringTypes): - root, ext = os.path.splitext(file_name) - f = root + "-tmp" + ext - return f - else: - return "tmp" - -# Same function as strip_extension, different name, as per scsh, in fact. -# -def file_name_sans_extension(s): - return strip_extension(s) - -# /a/b.t -> b.t d/e.ext -> e.ext -# file-name-sans-path -def strip_path(s): - import os - head, tail = os.path.split(s) - return tail - -# does s start with a "/" ? -# return True or False -# -# for windows return True when drive letter, e.g. C, or even \\ (backslash): -def slash_start_qm(s): - import types - import string - if isinstance(s, types.StringTypes): - if len(s) > 0: - if (s.startswith("/") or s.startswith("\\")): - return True - else: - if (os.name == 'nt' and len(s) > 1): - # for windows check if the start is a drive letter - drive_letter_ls = [dl + ':' for dl in string.ascii_uppercase] - if (s[0:2] in drive_letter_ls): - return True - return False - -# return a string that contains the date/time -# e.g. "2006-01-02_2216.03" -# -def unique_date_time_str(): - import time - lt = time.strftime("%Y-%m-%d_%H%M", time.localtime()) - return lt - -# return a list that has only every-nth members; -# e.g. @code{every_nth ([0,1,2,3,4,5,6,7,8],2)} -> [0,2,4,6,8] -# @code{every_nth ([0,1,2,3,4,5,6,7,8],3)} -> [0,3,6] -# -# @var{n} must be positive -# -def every_nth(ls, n): - - elements = range(0,len(ls),n) - a =[] - for i in elements: - a.append(ls[i]) - return a - -# now usefull in testing -# -# residue_atoms must be a list -# -def get_atom_from_residue(atom_name, residue_atoms, alt_conf): - - """Get atom_info fomr a residue. - residue_atoms must be a list - """ - - if ((isinstance(residue_atoms, list)) and - (residue_atoms != [])): - for residue_atom in residue_atoms: - if (residue_atom[0][0] == atom_name and - residue_atom[0][1] == alt_conf): - return residue_atom - # print "BL WARNING:: no atom name %s found in residue" %atom_name - return False # no residue name found fail save - - -# return atom info or False (if atom not found). -# -def get_atom(imol, chain_id, resno, ins_code, atom_name, alt_conf_internal=""): - - res_info = residue_info(imol, chain_id, resno, "") - - if (not res_info): - return False - else: - ret = get_atom_from_residue(atom_name, res_info, alt_conf_internal) - return ret - -# -def residue_info_dialog_displayed_qm(): - if (residue_info_dialog_is_displayed == 1): - return True - else: - return False - -# multi_read pdb reads all the files matching -# @code{@emph{glob_pattern}} in -# directory @code{@emph{dir}}. Typical usage of this might be: -# @code{multi_read_pdb("a*.pdb",".")} -# BL says: in windows dir needs the 'C:/' pattern, '/c/'won't work -# -def multi_read_pdb(glob_pattern, dir): - import glob, os - patt = os.path.normpath(dir+'/*.'+glob_pattern) - all_files = glob.glob(patt) - for file in all_files: - print "BL INFO:: reading ", file - read_pdb(file) - -# read_pdb_all reads all the "*.pdb" files in the current directory. -# -def read_pdb_all(): - import glob, os - recentre_status = recentre_on_read_pdb() - set_recentre_on_read_pdb(0) - patt = os.path.normpath(os.path.abspath(".")+'/*.pdb') - all_files = glob.glob(patt) - for file in all_files: - print "BL INFO:: reading ", file - read_pdb(file) - set_recentre_on_read_pdb(recentre_status) - -# return False if dir_name is a file or we can't do the mkdir -def coot_mkdir(dir_name): - import os - if (os.path.isfile(dir_name)): - return False - else: - if (os.path.isdir(dir_name)): - return True - else: - os.mkdir(dir_name) - return True - -# return the view matrix (useful for molscript, perhaps). -# BL says: like all matrices is a python list [...] -# -def view_matrix(): - return [get_view_matrix_element(row_number,column_number) for row_number in range(3) for column_number in range(3)] - -# return the transposed view matrix (useful for molscript, perhaps). -# BL says: like all matrices is a python list [...] -# -def view_matrix_transp(): - return [get_view_matrix_element(column_number,row_number) for row_number in range(3) for column_number in range(3)] - -# return the view quaternion -# -def view_quaternion(): - - ret = map(get_view_quaternion_internal,[0,1,2,3]) - return ret - -# Return the view number -# -def add_view(position, quaternion, zoom, view_name): - - args = position + quaternion - args.append(zoom) - args.append(view_name) - ret = add_view_raw(*args) - return ret - -# Convert a view matrix to a view quaternion to set Coot view internals. -# -def matrix2quaternion(m00, m10, m20, m01, m11, m21, m02, m12, m22): - - import math - - # From an idea by "Christian" at euclidianspace.com. The - # rotation matrix is special orthogonal, so (1 + trace) > 0. So - # we can simply do a sqrt on the 4 trace variants. Most of the - # code here is simply recovering the sign. - - # return x with the sign of y - def convert_sign(x, y): - if (x > 0 and y > 0): - return x - elif (x < 0 < y): - return -x - elif (x > 0 > y): - return -x - else: - return x - - pw = 1 + m00 + m11 + m22 - px = 1 + m00 - m11 - m22 - py = 1 - m00 + m11 - m22 - pz = 1 - m00 - m11 + m22 - - pr = [] - for v in [pw, px, py, pz]: - if v < 0: - v1 = 0 - else: - v1 = v - pr.append(math.sqrt(v1) / 2) - - ls = map(convert_sign, pr[1:], [m21 - m12, m02 - m20, m10 - m01]) - - ls.append(pr[0]) - - return ls - -# e.g -# matrix2quaternion(0.0347695872187614, 0.773433089256287, 0.632923781871796, -# 0.774806916713715, 0.379149734973907, -0.505885183811188, -# -0.631241261959076, 0.507983148097992, -0.586078405380249) -# -> -# [-0.55715757608, -0.694704711, -7.549694273e-4, 0.45492890477] or similar - -# Set the view matrix using matrix->quaternion. -# -# Useful for using a view matrix from another program, perhaps. -# -def set_view_matrix(m00, m10, m20, m01, m11, m21, m02, m12, m22): - - set_view_quaternion(matrix2quaternion(m00, m10, m20, - m01, m11, m21, - m02, m12, m22)) - -# Miguel's molecular orientation axes -# -def miguels_axes(): - set_axis_orientation_matrix(*view_matrix()) - set_axis_orientation_matrix_usage(1) - -# Return the molecule centre as a list of 3 numbers. -# -# Note: mol_cen could contain values less than -9999. -# -def molecule_centre(imol): - return [coot.molecule_centre_internal(imol,0), - coot.molecule_centre_internal(imol,1), - coot.molecule_centre_internal(imol,2)] - -# Move the centre of molecule number imol to the current screen centre -# -def move_molecule_to_screen_centre(imol): - if valid_model_molecule_qm(imol): - rotate_centre = rotation_centre() - coot.translate_molecule_by(imol,(rotate_centre[0]-molecule_centre(imol)[0]), - (rotate_centre[1]-molecule_centre(imol)[1]), - (rotate_centre[2]-molecule_centre(imol)[2])) -# This is a short name for the above. -# deftexi move_molecule_here -move_molecule_here = move_molecule_to_screen_centre - -# Return a nine-membered list of numbers. -# -def identity_matrix(): - return [1,0,0,0,1,0,0,0,1] - -# e.g. translation('x',2) -# -> [2, 0, 0] -# Return: False on error -# -def translation(axis,length): - import operator -# BL says: we dont check if axis is string, yet at least not directly - if (operator.isNumberType(length)): - if (axis=="x"): - return [length,0,0] - elif (axis=="y"): - return [0,length,0] - elif (axis=="z"): - return [0,0,length] - else: - print "symbol axis: ", axis, " incomprehensible" - return False - else: - print "incomprehensible length argument: ",length - return False - -# Rotate degrees about screen axis, where axis is either 'x', 'y' or 'z'. -# -def rotate_about_screen_axis(axis,degrees): - import math, operator - - def deg_to_rad(degs): - return (degs * 3.1415926 /180.0) - - def simple_rotation_x(alpha): - cos_alpha = math.cos(alpha) - sin_alpha = math.sin(alpha) - return [1,0,0,0,cos_alpha,-sin_alpha,0,sin_alpha,cos_alpha] - - def simple_rotation_y(alpha): - cos_alpha = math.cos(alpha) - sin_alpha = math.sin(alpha) - return [cos_alpha,0,sin_alpha,0,1,0,-sin_alpha,0,cos_alpha] - - def simple_rotation_z(alpha): - cos_alpha = math.cos(alpha) - sin_alpha = math.sin(alpha) - return [cos_alpha,-sin_alpha,0,sin_alpha,cos_alpha,0,0,0,] - -# BL says: I dont know what the next 2 defines are for... -# looks not used and/or useless to me -# seems that only 2nd matrix is used and not view_matrix! - def vm():view_matrix() - def mult(mat1,mat2):mat2 -# end of uselessness... - - if (operator.isNumberType(degrees)): - if (axis=="x"): - mult(view_matrix(),simple_rotation_x(deg_to_rad(degrees))) - elif (axis=="y"): - mult(view_matrix(),simple_rotation_y(deg_to_rad(degrees))) - elif (axis=="z"): - mult(view_matrix(),simple_rotation_z(deg_to_rad(degrees))) - else: - print "symbol axis: ", axis, " incomprehensible" - else: - print "incomprehensible length argument: ", degrees - - -# Support for old toggle functions. (consider instead the raw -# functions use the direct set_displayed functions). -# -def toggle_display_map(imol, idummy): - if (map_is_displayed(imol) == 0): - set_map_displayed(imol, 1) - else: - set_map_displayed(imol, 0) - -# toggle the display of imol -# -def toggle_display_mol(imol): - if (mol_is_displayed(imol) == 0): - set_mol_displayed(imol, 1) - else: - set_mol_displayed(imol, 0) - -# toggle the active state (clickability) of imol -# -def toggle_active_mol(imol): - if (mol_is_active(imol) == 0): - set_mol_active(imol, 1) - else: - set_mol_active(imol, 0) - -# return a python (list) representation of molecule imol, or False if we can't -# do it (imol is a map, say) -# -def python_representation(imol): - - if (not valid_model_molecule_qm(imol)): - return False - else: - ls = [] - def r_info(imol, chain_id, n): - res_name = resname_from_serial_number(imol, chain_id, n) - res_no = seqnum_from_serial_number(imol, chain_id, n) - ins_code = insertion_code_from_serial_number(imol, chain_id, n) - return [res_no, ins_code, res_name, residue_info(imol, chain_id, res_no, ins_code)] - - ls = [map(lambda chain_id: [chain_id, map(lambda serial_number: r_info(imol, chain_id, serial_number), range(chain_n_residues(chain_id, imol)))], chain_ids(imol))] - return ls - -# reorder chains -# -def reorder_chains(imol): - - # reorder elements of chain_list: e.g. - # - # chain_list: [["C", [xx]], ["A", [xx]], ["B", [xx]]] - # - def reorder_chains_in_model(chain_list): - map(lambda model: model.sort(), chain_list) - - p_rep = python_representation(imol) - if (type(p_rep) is ListType): - reorder_chains_in_model(p_rep) - clear_and_update_molecule(imol, p_rep) - - -# transform a coordinates molecule by a coot-rtop (which is a Python -# expression of a clipper::RTop), i.e. a list of a 9-element list and -# a 3 element list, e.g. [[1, 0, 0, 0, 1, 0, 0, 0, 1], [4.5, 0.4, 1.2]] -# -def transform_coords_molecule(imol, rtop): - - ls = [] - for i in rtop: - for j in i: - ls.append(j) - - transform_molecule_by(imol, *ls) - -# @code{transform_map(imol, mat, trans, about_pt, radius, space_group, cell)} -# -# where space_group is a HM-symbol and cell is a list of 6 -# parameters, where the cell angles are in degrees. -# -# or @code{transform_map(imol, trans, about_pt, radius)} for a simple translation -# -# or @code{transform_map(imol, trans, radius)} when using the default -# rotation-centre as the about-pt -# -# returns new map mol number or None if no map could be transformed/created -# -def transform_map(*args): - - ret = None - def tf(imol, mat, trans, about_pt, radius, space_group, cell): - return transform_map_raw(imol, - mat[0], mat[1], mat[2], - mat[3], mat[4], mat[5], - mat[6], mat[7], mat[8], - trans[0], trans[1], trans[2], - about_pt[0], about_pt[1], about_pt[2], - radius, - space_group, - cell[0], cell[1], cell[2], - cell[3], cell[4], cell[5]) - - # main line - if (len(args)==7): - ret = tf(args[0], args[1], args[2], args[3], args[4], args[5], args[6]) - # imol_map mat trans about_pt radius: - elif (len(args)==5): - imol = args[0] - ret = tf(imol, args[1], args[2], args[3], args[4], - space_group(imol), cell(imol)) - # no matrix specified: - elif (len(args)==4): - imol = args[0] - ret = tf(imol, identity_matrix(), args[1], args[2], args[3], - space_group(imol), cell(imol)) - # no matrix or about point specified: - elif (len(args)==3): - imol = args[0] - ret = tf(args[0], identity_matrix(), args[1], rotation_centre(), - args[2], space_group(imol), cell(imol)) - else: - print "arguments to transform-map incomprehensible: args: ",args - return ret - - -# return then NCS master of the first molecule that has ncs. -# -# return "" on fail to find an ncs chain -# -def get_first_ncs_master_chain(): - - r = "" - for mols in model_molecule_list(): - ncs_masters = ncs_master_chains(mols) - if ncs_masters: - return ncs_masters[0] - return r - -# Define a map transformation function that obeys Lapthorn's Law of -# NCS Handling Programs -# -# typical usage: transform_map_using_lsq_matrix(1, "A", 10, 30, 0, "A", 10, 30, 2, rotation_centre(), 6) -# -# Remember, that now the about-pt is the "to" point, i.e. the maps are brought from -# somewhere else and generated about the about-pt. -# -def transform_map_using_lsq_matrix(imol_bref, ref_chain, ref_resno_start, ref_resno_end, - imol_mov, mov_chain, mov_resno_start, mov_resno_end, - imol_map, about_pt, radius): - - clear_lsq_matches() - add_lsq_match(ref_resno_start, ref_resno_end, ref_chain, - mov_resno_start, mov_resno_end, mov_chain, 1) - space_group = symmetry_operators_to_xHM(symmetry_operators(imol_ref)) - cell_params = cell(imol_ref) - - if not (space_group and cell): - message = "Bad cell or symmetry for molecule" + str(cell) + str(space_group) + str(imol_ref) - print "Bad cell or symmetry for molecule", message - ret = -1 # invalid mol! or return message!? - - else: - rtop = apply_lsq_matches(imol_ref, imol_mov) - ret = transform_map(imol_map, rtop[0], rtop[1], about_pt, radius, - space_group, cell_params) - return ret - -# Make the imol-th map brighter. -# -# Scale_factor > 1 makes brighter... -# -def brighten_map(imol, scale_factor): - - from types import ListType - - if valid_map_molecule_qm(imol): - current_colour = map_colour_components(imol) - if type(current_colour) is ListType: - new_v = [] - for i in range(len(current_colour)): - new_v.append(current_colour[i] * float(scale_factor)) - if new_v[i] < 0.05: - new_v[i] = 0.05 - elif new_v[i] > 1.0: - new_v[i] = 1.0 - else: - pass - set_map_colour(imol, *new_v) - else: - print "bad non-list current-colour ", current_colour - graphics_draw() - -# Make all maps brighter -# -def brighten_maps(): - map(lambda imap: brighten_map(imap, 1.25), map_molecule_list()) - -# Make all maps darker -# -def darken_maps(): - map(lambda imap: brighten_map(imap, 0.8), map_molecule_list()) - -# return a list of chain ids for given molecule number @var{imol}. -# return empty list on error -# -def chain_ids(imol): - - chain_id_is = [] - number_of_chains = n_chains(imol) - for chain_no in range(number_of_chains): - chain_id_is.append(chain_id(imol,chain_no)) - return chain_id_is - -# convert from interface name to schemisch name to be equivalent to Paul's naming -# -# return True or False -# -def is_solvent_chain_qm(imol,chain_id): - if (is_solvent_chain_p(imol,chain_id)==1): return True - else: return False - -# convert from interface name to schemisch name to be equivalent to Paul's naming -# -# return True or False -# -def is_protein_chain_qm(imol, chain_id): - return is_protein_chain_p(imol, chain_id) == 1 - -# convert from interface name to schemisch name to be equivalent to Paul's naming -# -# return True or False -# -def is_nucleotide_chain_qm(imol, chain_id): - return is_nucleotide_chain_p(imol, chain_id) == 1 - -# python (schemeyish) interface to eponymous scripting interface function!? -# return True or False -# -def valid_model_molecule_qm(imol): - if (coot.is_valid_model_molecule(imol)==1): return True - else: return False - -# python (schemeyish) interface to eponymous scripting interface function. -# return True or False -# -def valid_map_molecule_qm(imol): - if (coot.is_valid_map_molecule(imol)==1): return True - else: return False - -# convenience function (slightly less typing). -# -# Return True or False -# -def valid_refinement_map_qm(): - return valid_map_molecule_qm(imol_refinement_map()) - -# python (schemeyish) interface to shelx molecule test -# -# Return True or False -# -def shelx_molecule_qm(imol): - return is_shelx_molecule(imol) == 1 - -# python (schemeyish) interface to the function that returns whether or not a map -# is a difference map. -# -# Return True or False. -# -def is_difference_map_qm(imol_map): - if (not valid_map_molecule_qm(imol_map)): - return False - else: - return map_is_difference_map(imol_map) == 1 - -# Does residue resno with insertion code ins_code of chain chain_id -# and in molecule number imol exist? -# -# Return True or False -# -def residue_exists_qm(imol,chain_id,resno,ins_code): - return does_residue_exist_p(imol,chain_id,resno,ins_code) == 1 - -# Does the residue contain hetatoms? -# Return True or False. -# -def residue_has_hetatms_qm(imol, chain_id, res_no, ins_code): - return residue_has_hetatms(imol, chain_id, res_no, ins_code) == 1 - -# Return a list of 3 float for the centre of mas of molecule number imol. -# -# on failure return False. -# -def centre_of_mass(imol): - centre = eval(centre_of_mass_string(imol)) - if (centre == 0): - print "molecule number",imol,"is not valid" - return False - else: - print "Centre of mass for molecule {0!s} is {1!s}".format(imol, centre) - # for use somewhere let's return the centre - return centre - -# Return as a list the occupancy, temperature_factor, x y z coordinates -# of the given atom. -# (the x,y,z are in Cartesian Angstroms). -# -# on error (e.g. atom not found) return False -# -def atom_specs(imol, chain_id, resno, ins_code, atom_name, alt_conf): - - return atom_info_string(imol, chain_id, resno, ins_code, atom_name, alt_conf) - -def atom_spec2residue_spec(atom_spec): - return atom_spec[2:][0:3] - -# return a guess at the map to be refined (usually called after -# imol_refinement_map returns -1) -# -# Basically uses the first not difference map we find! -# -def guess_refinement_map(): - - map_list = map_molecule_list() - if not map_list: - return -1 # failed to find a map - else: - for map_mol in map_list: - if map_is_difference_map(map_mol) == 0: - return map_mol - print "BL WARNING:: we couldnt find a non difference map for fitting!" - return -1 - - -# Ian Tickle says (as far as I can understand) that the target rmsd -# should be 0.25 or thereabouts. You can over-ride it now. -# -# BL says:: still, I dont get it to 0.25, so we make it 1.0 -# Even setting it to 0.8 (more or less arbitratry, but accounting for -# some redundancy in the parameters (Ian's comment)) is not enough, I think -# It seems reality is different to theory, here at least... -global target_auto_weighting_value -target_auto_weighting_value = 1.0 - -# Set the refinement weight (matrix) by iterating the refinement and -# varying the weight until the chi squares (not including the -# non-bonded terms) reach 1.0 =/- 10%. It uses sphere refinement. -# The refinement map must be set!! At the end show the new weight in -# the status bar. Seems to take about 5 rounds. (bails out after 20) -# -def auto_weight_for_refinement(): - - global target_auto_weighting_value - # return a pair of the imol and a list of residue specs. - # or False if that is not possible - def sphere_residues(radius): - active_atom = active_residue() - if not active_atom: # check for list? - print "No active atom" - return False - else: - centred_residue = active_atom[1:4] - imol = active_atom[0] - other_residues = residues_near_residue(imol, centred_residue, radius) - all_residues = [centred_residue] - if (isinstance(other_residues, list)): - all_residues += other_residues - return [imol, all_residues] - - # the refinement function that is run and returns nice refinement - # results - # - def refinement_func(): - sr = sphere_residues(3.5) - if sr: - ret = with_auto_accept([refine_residues, sr[0], sr[1]]) - return ret - #return with_auto_accept([refine_residues, sr[0], sr[1]]) - else: - return False - - # get rid of non-bonded chi-squared results from the input list ls. - # - def no_non_bonded(ls): - ret = [] - if ls: - for item in ls: - if not (item[0] == "Non-bonded"): - ret.append(item) - return ret - - # return False or a number, which is the current overweighting of the - # density terms. (of course, when not overweighted, the geometric - # chi squareds will be about 1.0). - # - def weight_scale_from_refinement_results(rr): - if not rr: # check for list? - return False - else: - nnb_list = no_non_bonded(rr[2]) - chi_squares = [x[2] for x in nnb_list] - n = len(chi_squares) - summ = sum(chi_squares) - if n == 0: - return False - else: - return summ/n - - # main body - # - results = refinement_func() - n_trials = 0 - while results: - av_rms_d = weight_scale_from_refinement_results(results) - print "av_rms_d:", av_rms_d - if not av_rms_d: # check for number? - return False - if n_trials > 20: - print "BL INFO:: refinement did not converge, bailing out" - return False - if ((target_auto_weighting_value * 1.1) > av_rms_d > (target_auto_weighting_value * 0.9)): - # done - s = "Success: Set weight matrix to " + str(matrix_state()) - add_status_bar_text(s) - break - else: - # more refinement required - - # squared causes ringing, - # as does 1.5. - # Simple is overdamped. - current_weight = matrix_state() - new_weight = (target_auto_weighting_value * current_weight) / av_rms_d - print "INFO:: setting refinement weight to {0!s} from * {1!s} / {2!s}".format(new_weight, current_weight, av_rms_d) - if (new_weight < 2): - # weight refinement not converging - print "BL INFO:: not convering, weight to set was", new_weight - set_matrix(new_weight) - results = refinement_func() - n_trials += 1 - - return True # return successful termination... - -# Print the sequence of molecule number @var{imol} -# -# This is not really a util, perhaps it should be somewhere else? -# -def print_sequence(imol): - - for chain in chain_ids(imol): - print_sequence_chain(imol,chain) - -# simple utility function to return the contents of a file as a string. -# -def pir_file_name2pir_sequence(pir_file_name): - import os - if (not os.path.isfile(pir_file_name)): - return False - else: - try: - fin = open(pir_file_name, 'r') - str = fin.read() - fin.close() - return str - except: - return False - -# Associate the contents of a PIR file with a molecule. -# -def associate_pir_file(imol, chain_id, pir_file_name): - seq_text = pir_file_name2pir_sequence(pir_file_name) - if seq_text: - assign_pir_sequence(imol, chain_id, seq_text) - else: - print "WARNING:: associate-pir-file: bad text for", pir_file_name - -# Associate the contents of a fasta file with a molecule. -# -def associate_fasta_file(imol, chain_id, pir_file_name): - seq_text = pir_file_name2pir_sequence(pir_file_name) - if seq_text: - assign_fasta_sequence(imol, chain_id, seq_text) - else: - print "WARNING:: associate-fasta-file: bad text for", pir_file_name - - -# comma key hook -def graphics_comma_key_pressed_hook(): - pass - -# dot key hook -def graphics_dot_key_pressed_hook(): - pass - -# a list of [code, key, name, thunk] -# e.g. [103, "g", "Goto Blob", blob_under_pointer_to_screen_centre()] - -global key_bindings -# we shall see if it exists, if not initialize it -try: - key_bindings -except: - key_bindings = [] - -def decode_key(key_val_name): - try: - import gtk - key_value = int(gtk.gdk.keyval_from_name(key_val_name)) - # on some windows: special characters seem to have high value, - # so need to convert these properly too - if (not key_value or key_value >= 100000): - # new python needs a long there!? I hope it wont harm old!? - new_val = long(ord(key_val_name)) - key_value = int(gtk.gdk.unicode_to_keyval(new_val)) - return key_value - except: - return key_sym_code(key_val_name) - -# Add a key binding -# -# with a given name, key (e.g. "x" or "S") and the function to run -# (a thunk) when that key is pressed. -# -def add_key_binding(name, key, thunk): - from types import IntType, StringType - global key_bindings, std_key_bindings - std_keys = [] - if (use_gui_qm): - std_keys = [elem[1] for elem in std_key_bindings] - keys = [elem[1] for elem in key_bindings] - codes = [elem[0] for elem in key_bindings] - if (key in std_keys): - print "INFO:: you shall not overwrite a standard key binding ({0!s})".format(key) - else: - if (type(key) is IntType): - if (key in keys): - print "INFO:: you are overwriting existing key", key - key_bindings.pop(keys.index(key)) - key_bindings.append([key, key, name, thunk]) - elif (type(key) is StringType): - code = decode_key(key) - if (code in codes): - print "INFO:: you are overwriting existing key (from code)", key - key_bindings.pop(codes.index(code)) - if "Control_" in key: - code = decode_key(key[-1]) - if (("Control_" in key) or not (code == -1)): - key_bindings.append([code, key, name, thunk]) - else: - print "INFO:: key {0!s} not found in code table".format(key) - else: - print "BL WARNING:: invalid key", key - - -# general key press hook, not for public use!! -# -def graphics_general_key_press_hook(key, control_flag = 0): - global key_bindings - # print "graphics_general_key_press_hook(): Key %s was pressed" %key - if control_flag: - codes = [elem[0] for elem in key_bindings if "Control_" in elem[1]] - funcs = [elem[3] for elem in key_bindings if "Control_" in elem[1]] - else: - codes = [elem[0] for elem in key_bindings if not "Control_" in elem[1]] - funcs = [elem[3] for elem in key_bindings if not "Control_" in elem[1]] - if (key in codes): - index = codes.index(key) - func = funcs[index] - # print "BL DEBUG:: index and executing:", index, func - apply(func) - else: - if coot_has_guile() and is_windows(): - run_scheme_command("(graphics-general-key-press-hook " + \ - str(key) + \ - ")") - print "Key {0!s} not found in (python) key bindings".format(key) - - -# Function requested by Mark White. -# -# read XtalView (and maybe other) .vu files and convert them into generic -# objects. -# -# Pass the filename and an object name e.g. -# read_vu_file("axes.vu", "axes") -# -# Returns: nothing interesting. -# -def read_vu_file(filename, obj_name): - - from types import StringType - from operator import isNumberType - - def colour_from_number(obj): - if type(obj) is StringType: - return obj - elif isNumbertype(obj): - if (obj == 0): - return "white" - else: - return "red" - else: - return "white" - - # main body - n = new_generic_object_number(obj_name) - fin = open(filename, 'r') - lines = fin.readlines() - fin.close() - for line in lines: - current_line = line.split() - if len(current_line) == 7: - colour = colour_from_number(current_line[-1]) - try: - coords = map(float, current_line[0:-1]) - except: - print "BL WARNING:: cannot make float from cordinates", current_line[0:-1] - return - to_generic_object_add_line(n, colour, 2, - *coords) - set_display_generic_object(n, 1) - - -# residue_test_func is a function that takes 4 arguments, the -# chain_id, resno, inscode and residue_serial_number (should it be -# needed) and returns either False or return something interesting -# (e.g. text for a button label). -# -# Return a list of residues, each of which has a return value at the -# start, ie. [return_value, chain_id, res_no, ins_code] -# -def residues_matching_criteria(imol, residue_test_func): - - chain_list = chain_ids(imol) - seq_residue_list = [] - alt_conf_residue_list = [] - - for chain_id in chain_list: - for serial_number in range(chain_n_residues(chain_id,imol)): - res_no = seqnum_from_serial_number(imol, chain_id, serial_number) - ins_code = insertion_code_from_serial_number(imol, chain_id, serial_number) - r = residue_test_func(chain_id, res_no, ins_code, serial_number) - if r: - seq_residue_list.append([chain_id, res_no, ins_code]) - if seq_residue_list: - return seq_residue_list - else: - return False - -# Return residue specs for all residues in imol (each spec is preceeded by True) -# -def all_residues(imol): - return residues_matching_criteria(imol, lambda chain_id, resno, ins_code, serial: True) - -# Return a list of all residues that have alt confs: where a residue -# is specified thusly: [[chain_id, resno, ins_code], [...] ] -# -def residues_with_alt_confs(imol): - - # return False if there are no atoms with alt-confs, else return - # a list of the residue's spec [chain_id, res_no, ins_code] - def alt_func1(chain_id, res_no, ins_code, res_serial_no): - r = False - atom_ls = residue_info(imol, chain_id, res_no, ins_code) - for i in range(len(atom_ls)): - alt_conf_str = atom_ls[i][0][1] - if alt_conf_str: - r = True - break - return r - - return residues_matching_criteria(imol, lambda chain_id, res_no, ins_code, res_serial_no: alt_func1(chain_id, res_no, ins_code, res_serial_no)) - -# Return a list of all the altconfs in the residue. -# Typically this will return [""] or ["A", "B"] -# -def residue_alt_confs(imol, chain_id, res_no, ins_code): - - atom_ls = residue_info(imol, chain_id, res_no, ins_code) - alt_confs = [] - - if atom_ls: - for i in range(len(atom_ls)): - alt_conf_str = atom_ls[i][0][1] - if not alt_conf_str in alt_confs: - alt_confs.append(alt_conf_str) - return alt_confs - - -# Return a list of all atoms that have zero occupancy: where an atom -# is specified thusly: [[chain_id, resno, ins_code, name, altconf], [...] ] -# -def atoms_with_zero_occ(imol): - - r = [] - for chain_id in chain_ids(imol): - n_residues = chain_n_residues(chain_id, imol) - for serial_number in range(n_residues): - - res_name = resname_from_serial_number(imol, chain_id, serial_number) - res_no = seqnum_from_serial_number(imol, chain_id, serial_number) - ins_code = insertion_code_from_serial_number(imol, chain_id, serial_number) - res_info = residue_info(imol, chain_id, res_no, ins_code) - for atom_info in res_info: - occ = atom_info[1][0] - name = atom_info[0][0] - alt_conf = atom_info[0][1] - if (occ < 0.01): - text = str(imol) + " " + chain_id + " " + \ - str(res_no) + " " + name - if (alt_conf): - text += " " - text += alt_conf - r.append([text, imol, chain_id, res_no, ins_code, name, alt_conf]) - - return r - - -# simple extraction function -def res_spec2chain_id(res_spec): - - """simple extraction function""" - - if not res_spec: - return False - if (len(res_spec) == 4): - return res_spec[1] - if (len(res_spec) == 3): - return res_spec[0] - return False - -# simple extraction function -def res_spec2res_no(res_spec): - - """simple extraction function""" - - if not res_spec: - return False - if (len(res_spec) == 4): - return res_spec[2] - if (len(res_spec) == 3): - return res_spec[1] - return False - -# simple extraction function -def res_spec2ins_code(res_spec): - - """simple extraction function""" - - if not res_spec: - return False - if (len(res_spec) == 4): - return res_spec[3] - if (len(res_spec) == 3): - return res_spec[2] - return False - - -# Return False if no atom can be found given the spec else return a list -# consisting of the atom name and alt-conf specifier. -# -# Choose an atom that is called " CA ". Failing that choose the -# first atom. -# -def residue_spec2atom_for_centre(imol, chain_id, res_no, ins_code): - - from types import ListType - # residue-info can return False - atom_ls = residue_info(imol, chain_id, res_no, ins_code) - - centre_atom_name_alt_conf = False - - if type(atom_ls) is ListType: - for i in range(len(atom_ls)): - alt_conf_str = atom_ls[i][0][1] - atom = atom_ls[i][0][0] - if (atom == " CA "): - centre_atom_name_alt_conf = [atom, alt_conf_str] - break - if (not centre_atom_name_alt_conf) and (len(atom_ls)>0): - # take the first atom - centre_atom_name_alt_conf = atom_ls[0][0][0:2] - - return centre_atom_name_alt_conf - - -def set_go_to_atom(res_spec): - set_go_to_atom_chain_residue_atom_name( - res_spec2chain_id(res_spec), - res_spec2res_no(res_spec), - " CA ") - - -def update_go_to_atom_from_current_atom(): - - active_atom = active_residue() - if active_atom: - imol = active_atom[0] - chain_id = active_atom[1] - resno = active_atom[2] - ins_code = active_atom[3] - atom_name = active_atom[4] - alt_conf = active_atom[5] - go_to_atom_imol_current = go_to_atom_molecule_number() - set_go_to_atom_molecule(imol) - # if imol != goto_atom_imol_current - update_go_to_atom_window_on_other_molecule_chosen(imol) - set_go_to_atom_chain_residue_atom_name(chain_id, resno, atom_name) - - -def flip_active_ligand(): - active_atom = active_residue() - imol = active_atom[0] - chain_id = active_atom[1] - resno = active_atom[2] - ins_code = active_atom[3] - atom_name = active_atom[4] - alt_conf = active_atom[5] - flip_ligand(imol, chain_id, resno) - -# Typically one might want to use this on a water, but it deletes the -# nearest CA currently... Needs a re-think. Should active-atom just -# return the nearest atom and not be clever about returning a CA. -# -def delete_atom_by_active_residue(): - - active_atom = active_residue() - if active_atom: - delete_atom(active_atom) - -# general mutate -# -# typically: -# -# overlay PTY onto given TYR -# -# delete speced TYR -# -# merge molecules PTY molecule int molecule number imol -# -# change resno of PTY to that of the speced TYR -# -# change chain id of PTY to that of speced TYR -# -# change chain ids with residue range for the PTY -# -def mutate_by_overlap(imol, chain_id_in, resno, tlc): - - # get_monomer_and_dictionary, now we check to see if we have a - # molecule already loaded that matches this residue, if we have, - # then use it. - # - def get_monomer_and_dictionary(tlc): - - have_tlc_molecule = False - for imol in model_molecule_list(): - nc = n_chains(imol) - if (nc == 1): - ch_id = chain_id(imol, 0) - nr = chain_n_residues(ch_id, imol) - if (nr == 1): - rn = resname_from_serial_number(imol, ch_id, 0) - if (rn == tlc): - have_tlc_molecule = imol - break - have_dict_for_tlc = monomer_restraints(tlc) - if ((not have_tlc_molecule) or (not have_dict_for_tlc)): - return get_monomer(tlc) - else: - print "we have dict and model for tlc already" - return have_tlc_molecule - - # - def mutate_it(): - imol_ligand = get_monomer_and_dictionary(tlc) - if not valid_model_molecule_qm(imol_ligand): - s = " Oops. Failed to get monomer " + str(tlc) - add_status_bar_text(s) - else: - delete_residue_hydrogens(imol_ligand, "A", 1, "", "") - delete_atom(imol_ligand, "A", 1, "", " OXT", "") - overlap_ligands(imol_ligand, imol, chain_id_in, resno) - match_ligand_torsions(imol_ligand, imol, chain_id_in, resno) - delete_residue(imol, chain_id_in, resno, "") - new_chain_id_info = merge_molecules([imol_ligand], imol) - print "INFO:: new_chain_id_info: ", new_chain_id_info - merge_status = new_chain_id_info[0] - if merge_status == 1: - new_chain_id = new_chain_id_info[1] - change_residue_number(imol, new_chain_id, 1, "", resno, "") - change_chain_id(imol, new_chain_id, chain_id_in, 1, resno, resno) - - replacement_state = refinement_immediate_replacement_state() - imol_map = imol_refinement_map() - set_refinement_immediate_replacement(1) - if imol_map == -1: - regularize_zone(imol, chain_id_in, resno, resno, "") - else: - spin_atoms = [" P ", " O1P", " O2P", " O3P"] - phos_dir = { - 'PTR': [" CZ ", " OH "], - 'SEP': [" CB ", " OG "], - 'TPO': [" CB ", " OG1"] } - if tlc in phos_dir.keys(): - dir_atoms = phos_dir[tlc] - else: - dir_atoms = False - refine_zone(imol, chain_id_in, resno, resno, "") - if dir_atoms: - spin_search(imol_map, imol, chain_id_in, resno, "", dir_atoms, spin_atoms) - refine_zone(imol, chain_id_in, resno, resno, "") - accept_regularizement() - set_refinement_immediate_replacement(replacement_state) - - set_mol_displayed(imol_ligand, 0) - set_mol_active(imol_ligand, 0) - - else: - # guess merge failed!?! - print "BL WARNING:: merge failed!?" - - # main line - # - # First, if there are multiple maps, force the user to choose one, - # rather than continuing. - # - imol_map = imol_refinement_map() - if (imol_map == -1): - map_mols = map_molecule_list() - if not map_mols: - print "BL WARNING:: no valid maps around! Cannot mutate." - else: - # BL says:: I dunno how to wait for the input from map selection since there is no return - # waiting for mouse/keyboard input may be an option but no curses on windows, maybe - # fix later, for now we use the first map - # show_select_map_dialog() - if len(map_mols) > 1: - print "BL INFO:: we use the first map! If you wanna use another one, please select from Model/Fit/Refine" - else: - print "BL INFO:: no refinement map set, will set first one for you!" - set_imol_refinement_map(map_mols[0]) - mutate_it() - else: - mutate_it() - -# A bit of fun -# -def phosphorylate_active_residue(): - - active_atom = active_residue() - imol = active_atom[0] - chain_id = active_atom[1] - resno = active_atom[2] - inscode = active_atom[3] - res_name = residue_name(imol, chain_id, resno, inscode) - - if res_name == 'TYR': - mutate_by_overlap(imol, chain_id, resno, "PTR") - elif res_name == 'SER': - mutate_by_overlap(imol, chain_id, resno, "SEP") - elif res_name == 'THR': - mutate_by_overlap(imol, chain_id, resno, "TPO") - else: - s = "Can't Phosphorylate residue of type " + res_name - info_dialog(s) - -# A function for Overlaying ligands. The transformation is applied -# to all the atoms of the molecule that contains the moving ligand. -# -def overlay_my_ligands(imol_mov, chain_id_mov, resno_mov, - imol_ref, chain_id_ref, resno_ref): - - imol_frag = new_molecule_by_atom_selection(imol_mov, - "//" + chain_id_mov + \ - "/" + str(resno_mov)) - rtop_i = overlap_ligands(imol_frag, imol_ref, chain_id_ref, resno_ref) - set_mol_displayed(imol_frag, 0) - transform_coords_molecule(imol_mov, rtop_i[0]) - -def label_all_CAs(imol): - - for chain_id in chain_ids(imol): - if not (is_solvent_chain_qm(imol, chain_id)): - n_residues = chain_n_residues(chain_id, imol) - for serial_number in number_list(0, n_residues): - res_name = resname_from_serial_number(imol, chain_id, serial_number) - res_no = seqnum_from_serial_number(imol, chain_id, serial_number) - ins_code = insertion_code_from_serial_number(imol, chain_id, serial_number) - add_atom_label(imol, chain_id, res_no, " CA ") - graphics_draw() - - -def label_all_atoms_in_residue(imol, chain_id, resno, inscode): - import types - - atom_list = residue_info(imol, chain_id, resno, inscode) - if type(atom_list) is ListType: - for atom_info in atom_list: - add_atom_label(imol,chain_id, resno, atom_info[0][0]) - graphics_draw() - -def label_all_active_residue_atoms(): - - active_atom = active_residue() - imol = active_atom[0] - chain_id = active_atom[1] - resno = active_atom[2] - inscode = active_atom[3] - - atom_list = residue_info(imol, chain_id, resno, inscode) - if type(atom_list) is ListType: - for atom_info in atom_list: - add_atom_label(imol,chain_id, resno, atom_info[0][0]) - graphics_draw() - -# Resets alt confs and occupancies of atoms in residue that have -# orphan alt-loc attributes -# -def sanitise_alt_confs(atom_info, atom_ls): - - # return a matching atom (name match) if it exists. Else return False - def name_match_qm(atom_1, atom_ls): - compound_name_1 = atom_1[0] - atom_name_1 = compound_name_1[0] - matchers = [] - for atom in atom_ls: - compound_name_2 = atom[0] - atom_name_2 = compound_name_2[0] - - if (atom_name_1 == atom_name_2): - matchers.append(atom) - - if matchers: - return matchers - else: - return False - - # main body - imol = atom_info[0] - chain_id = atom_info[1] - resno = atom_info[2] - inscode = atom_info[3] - atom_attribute_settings = [] # add to this - - for atom in atom_ls: - compound_name = atom[0] - atom_name = compound_name[0] - alt_conf = compound_name[1] - if (alt_conf != ""): - matchers = name_match_qm (atom, atom_ls) - if (len(matchers) == 1): - atom_attribute_settings.append([imol, chain_id, resno, inscode, atom_name, - alt_conf, "alt-conf", ""]) - else: - atom_attribute_settings.append([imol, chain_id, resno, inscode, atom_name, - alt_conf, "occ", ((shelx_molecule_qm(imol) and 11.0) or (1.0))]) - if (atom_attribute_settings != []): - set_atom_attributes(atom_attribute_settings) - if (residue_info_dialog_displayed_qm()): - residue_info_dialog(imol, chain_id, resno, inscode) - -# -def sanitise_alt_confs_in_residue(imol, chain_id, resno, inscode): - - atom_info = [imol, chain_id, resno, inscode, "dummy", "dummy"] - atom_ls = residue_info(imol, chain_id, resno, inscode) - sanitise_alt_confs(atom_info, atom_ls) - -# Resets alt confs and occupancies of atoms in residue that have -# orphan alt-loc attributes. Use the active-residue. -# -def sanitise_alt_confs_active_residue(): - active_atom = active_residue() - if active_atom: - imol = active_atom[0] - chain_id = active_atom[2] - resno = active_atom[2] - inscode = active_atom[2] - - atom_ls = residue_info(imol, chain_id, resno, inscode) - - if atom_ls: - sanitise_alt_confs(active_atom, atom_ls) - -def print_molecule_names(): - - map(lambda molecule_number: printf( " {0!s} {1!s}\n".format(molecule_number, molecule_name(molecule_number))), - molecule_number_list()) - -# save the dialog positions to the coot_dialog_positions.py file in ./coot-preferences -# -def save_dialog_positions_to_init_file(): - - import os - # return False on failure to find .coot.py (or .coot-preferences) - def dump_positions_to_file(positions, preferences=False): - home = 'HOME' - port = False - if (os.name == 'nt'): - home = 'COOT_HOME' - if preferences: - init_dir = os.path.join(os.getenv(home), - ".coot-preferences") - init_file = os.path.join(init_dir, - "saved_dialog_positions.py") - if (not os.path.isdir(init_dir)): - return False - port = open(init_file, 'w') - print "BL INFO:: writing dialog positions to .coot-preferences/saved_dialog_positions.py" - else: - init_file = os.path.join(os.getenv(home), - ".coot.py") - if (not os.path.isfile(init_file)): - return False - port = open(init_file, 'a') - print "BL INFO:: writing dialog positions to .coot.py" - - if port: - - port.write("# ----------------------------------------------------------") - port.write("# the following were written by extraction from a state file") - port.write("# ----------------------------------------------------------") - for position in positions: - port.write(position) - port.write("# -------------------------") - port.close() - else: - print "BL ERROR:: no valid port to write to!" - - # main line - state_file = "0-coot.state.py" - save_state() - if (not os.path.isfile(state_file)): - print "Ooops {0!s} does not exist (either guile enabled or problem writing the file".format(state_file) - else: - port = open("0-coot.state.py", 'r') - try: - lines = port.readlines() - except: - lines = [] - positions =[] - for line in lines: - if ("_dialog_position" in line): - print " Adding dialog position: ", line - positions.append(line) - elif ("set_go_to_atom_window_position" in line): - print " Adding dialog position: ", line - positions.append(line) - port.close() - - write_init_status = dump_positions_to_file(positions) - if (write_init_status == False): - # try to write a file to preferences - dump_positions_to_file(positions, preferences=True) - -# saves a string to a file! -# if the string is already present dont do anything -# optional arg: overwrite -# False - default -# True - overwrite file -# -def save_string_to_file(string, filename, overwrite=False): - - #home = 'HOME' - #if (os.name == 'nt'): - # home = 'COOT_HOME' - init_file = filename - if (os.path.isfile(init_file)): - # init file exists - if (overwrite): - port = open(init_file, 'w') - lines = [] - else: - port = open(init_file, 'r+') - lines = port.readlines() - else: - port = open(init_file, 'w') - lines = [] - string_written = False - for line in lines: - if string in line: - # line exists, dont write - string_written = True - break - if (not string_written): - # append the string - port.write((string + "\n")) - port.close() - - -# removes a line containg all strings of the given list from file -def remove_line_containing_from_file(remove_str_ls, filename): - - #home = 'HOME' - #if (os.name == 'nt'): - # home = 'COOT_HOME' - #init_file = os.path.join(os.getenv(home), ".coot.py") - init_file = filename - if (os.path.isfile(init_file)): - # init file exists - port = open(init_file, 'r') - lines = port.readlines() - port.close() - else: - print "BL INFO:: no {0!s} file, so cannot remove line".format(init_file) - lines = [] - if (lines): - patt = string.join(remove_str_ls,'|') - re_patt = re.compile(patt) - tmp_ls = [] - for line in lines: - result = re_patt.findall(line) - if (not len(result) == len(remove_str_ls)): - tmp_ls.append(line) - port = open(init_file, 'w') - lines = port.writelines(tmp_ls) - port.close() - -# multiple maps of varying colour from a given map. -# -def multi_chicken(imol, n_colours = False): - - def rotate_colour_map(col, degrees): - ret = [degrees/360 , col[1], col[2] - degrees/360] - # ??? not sure about 1st element, think mistake in Paul's scheme script - return ret - - start = 1.0 - stop = 6.0 - initial_colour = [0.2, 0.2, 0.8] - colour_range = 360 - - if (valid_map_molecule_qm(imol)): - if (not n_colours): - n_col = 10 - else: - n_col = n_colours - sigma = map_sigma(imol) - - print "range n_col returns: ", range(n_col) - - for icol in range(n_col): - new_map = copy_molecule(imol) - frac = icol / float(n_col) # need a float!! - contour_level_sigma = start + (stop - start) * frac - set_last_map_contour_level(sigma * contour_level_sigma) - set_last_map_colour(*rotate_colour_map(initial_colour, colour_range * frac)) - else: - print "BL INFO:: {0!s} is not valid map".format(imol) - - -# simple enumeration -# -def BALL_AND_STICK(): return 2 - -# hilight-colour is specified in degrees (round the colour wheel - -# starting at yellow (e.g. 230 is purple)) -# -def hilight_binding_site(imol, centre_residue_spec, hilight_colour, radius): - - if (valid_model_molecule_qm(imol)): - - other_residues = residues_near_residue(imol, centre_residue_spec, radius) - atom_sel_str = residue_spec2atom_selection_string(centre_residue_spec) - - imol_new = new_molecule_by_atom_selection(imol, atom_sel_str) - bb_type = 1 - draw_hydrogens_flag = draw_hydrogens_state(imol) - - set_mol_active(imol_new, 0) - set_show_environment_distances(1) - set_molecule_bonds_colour_map_rotation(imol_new, hilight_colour) - additional_representation_by_attributes(imol_new, - centre_residue_spec[0], - centre_residue_spec[1], - centre_residue_spec[1], - centre_residue_spec[2], - BALL_AND_STICK(), - bb_type, 6, - draw_hydrogens_flag) - - map(lambda spec: additional_representation_by_attributes(imol, - spec[0], - spec[1], - spec[1], - spec[2], - BALL_AND_STICK(), - bb_type, 6, - draw_hydrogens_flag), - other_residues) - -highlight_binding_site = hilight_binding_site # typo? - - -# Function based on Davis et al. (2007) Molprobity: all atom contacts -# and structure validation for proteins and nucleic acids, Nucleic -# Acids Research 35, W375-W383. -# -# "RNA sugar puckers (C3'endo or C2'endo) is strongly correlated -# to the perpendicular distance between the following (3') -# phosphate and either the plane of the base or the C1'-N1/9 -# glycosidic bond vector. [] .. a sugar pucker is very difficult -# to determine directly from the electron density at resolutions -# typical for RNAs." -# -# To paraphrase: -# The distance of the plane of the base to the following phosphate -# is highly correlated to the pucker of the ribose. -# -# An analysis of the structures in RNADB2005 shows that a critical -# distance of 3.3A provides a partition function to separate C2' from -# C3' endo puckering. Not all ribose follow this rule. There may be -# some errors in the models comprising RNADB2005. So we check the -# distance of the following phosphate to the plane of the ribose and -# record the riboses that are inconsitent. We also report puckers -# that are not C2' or C3'. The puckers are determined by the most -# out-of-plane atom of the ribose (the rms deviation of the 4 atoms -# in the plane is calculated, but not used to determine the -# puckering atom). -# -def pukka_puckers_qm(imol): - - import types - - residue_list = [] - crit_d = 3.0 # Richardson's grup value to partition C2'-endo from C3'-endo - - def add_questionable(r): - residue_list.append(r) - - def get_ribose_residue_atom_name(imol, residue_spec, pucker_atom): - r_info = residue_info(imol, residue_spec[0], residue_spec[1], residue_spec[2]) - t_pucker_atom = pucker_atom[0:3] + "*" - if (pucker_atom in map(lambda at: at[0][0], r_info)): - return pucker_atom - else: - return t_pucker_atom - - # main line - for chain_id in chain_ids(imol): - if (not is_solvent_chain_qm(imol, chain_id)): - n_residues = chain_n_residues(chain_id, imol) - - for serial_number in range(n_residues): - - res_name = resname_from_serial_number(imol, chain_id, serial_number) - res_no = seqnum_from_serial_number (imol, chain_id, serial_number) - ins_code = insertion_code_from_serial_number(imol, chain_id, serial_number) - - if (not res_name == "HOH"): - - residue_spec = [chain_id, res_no, ins_code] - pi = pucker_info(imol, residue_spec, 1) - if (pi): - if (type(pi) is ListType): - if (len(pi) == 4): - pucker_atom = pi[1] - if ((abs(pi[0]) > crit_d) and - (pucker_atom == " C2'")): - add_questionable([pucker_atom, residue_spec, - "Inconsistent phosphate distance for C2' pucker"]) - if ((abs(pi[0]) < crit_d) and - (pucker_atom == " C3'")): - add_questionable([pucker_atom, residue_spec, - "Inconsistent phosphate distance for C3' pucker"]) - if not ((pucker_atom == " C2'") or - (pucker_atom == " C3'")): - add_questionable([pucker_atom, residue_spec, - "puckered atom:" + pucker_atom]) - - if (len(residue_list) == 0): - info_dialog("No bad puckers.") - else: - buttons = [] - for residue in residue_list: - residue_spec = residue[1] - pucker_atom = residue[0] - at_name = get_ribose_residue_atom_name(imol, residue_spec, pucker_atom) - ls = [residue_spec[0] + " " + str(residue_spec[1]) + residue_spec[2] + \ - ": " + residue[2], - ["set_go_to_atom_molecule("+ str(imol) +")", - "set_go_to_atom_chain_residue_atom_name(" +\ - "\"" + str(residue_spec[0]) + "\", " +\ - str(residue_spec[1]) + ", " +\ - "\"" + str(at_name) + "\")"] - ] - buttons.append(ls) - dialog_box_of_buttons("Non-pukka puckers", - [370, 250], - buttons, - " Close ") - -# Run libcheck to convert from SMILES string -# -def new_molecule_by_smiles_string(tlc_text, smiles_text): - import shutil - if len(smiles_text) > 0: - - if ((len(tlc_text) > 0) and (len(tlc_text) < 4)): - three_letter_code = tlc_text - elif (len(tlc_text) > 0): - three_letter_code = tlc_text[0:3] - else: - three_letter_code = "DUM" - - # ok let's run libcheck - smiles_file = "coot-" + three_letter_code + ".smi" - libcheck_data_lines = ["N", - "MON " + three_letter_code, - "FILE_SMILE " + smiles_file, - ""] - log_file_name = "libcheck-" + three_letter_code + ".log" - pdb_file_name = "libcheck_" + three_letter_code + ".pdb" - cif_file_name = "libcheck_" + three_letter_code + ".cif" - - smiles_input = file(smiles_file,'w') - smiles_input.write(smiles_text) - smiles_input.close() - # now let's run libcheck (based on libcheck.py) - libcheck_exe_file = find_exe(libcheck_exe, "CCP4_BIN", "PATH") - - if (not libcheck_exe_file): - print " BL WARNING:: libcheck not found!" - else: - status = popen_command(libcheck_exe_file, [], libcheck_data_lines, log_file_name, True) - # the output of libcheck goes to libcheck.lib, we want it in - # (i.e. overwrite the minimal description in cif_file_name - if (status == 0): - if (os.path.isfile("libcheck.lib")): - # copy rather than rename file to avoid accession issues - shutil.copy("libcheck.lib", cif_file_name) - sc = rotation_centre() - imol = handle_read_draw_molecule_with_recentre(pdb_file_name, 0) - if (is_valid_model_molecule(imol)): - mc = molecule_centre(imol) - sc_mc = [sc[i]-mc[i] for i in range(len(mc))] - translate_molecule_by(imol, *sc_mc) - read_cif_dictionary(cif_file_name) - else: - print "OOPs.. libcheck returned exit status", status - - -# Generate restraints from the residue at the centre of the screen -# using PRODRG. Delete hydrogens from the residue because PRODRG has -# anomalous hydrogens. -# -def prodrg_ify(imol, chain_id, res_no, ins_code): - - new_mol = new_molecule_by_atom_selection(imol, - "//" + chain_id + "/" + str(res_no)) - - set_mol_active(new_mol, 0) - set_mol_displayed(new_mol, 0) - - prodrg_dir = "coot-ccp4" - res_name = residue_name(imol, chain_id, res_no, ins_code) - - if res_name: - make_directory_maybe(prodrg_dir) - prodrg_xyzin = os.path.join(prodrg_dir, "prodrg-in.pdb") - prodrg_xyzout = os.path.join(prodrg_dir, "prodrg-" + res_name + ".pdb") - prodrg_cif = os.path.join(prodrg_dir, "prodrg-" + res_name + ".cif") - prodrg_log = os.path.join(prodrg_dir, "prodrg.log") - - delete_residue_hydrogens(new_mol, chain_id, res_no, ins_code, "") - delete_residue_hydrogens(imol, chain_id, res_no, ins_code, "") # otherwise they fly - write_pdb_file(new_mol, prodrg_xyzin) - close_molecule(new_mol) - prodrg_exe = find_exe("cprodrg", "CCP4_BIN", "PATH") - if not prodrg_exe: - info_dialog("Cannot find cprodrg, so no prodrg-ifying of ligand possible") - else: - print "BL DEBUG:: now run prodrg with", prodrg_exe, \ - "XYZIN", prodrg_xyzin,\ - "XYZOUT", prodrg_xyzout,\ - "LIBOUT", prodrg_cif - status = popen_command(prodrg_exe, - ["XYZIN", prodrg_xyzin, - "XYZOUT", prodrg_xyzout, - "LIBOUT", prodrg_cif], - ["MINI PREP", "END"], - prodrg_log, - True) - if status == 0: - read_cif_dictionary(prodrg_cif) - imol_new = handle_read_draw_molecule_with_recentre(prodrg_xyzout, 0) - rn = residue_name(imol, chain_id, res_no, ins_code) - with_auto_accept([regularize_zone, imol_new, "", 1, 1, ""]) - overlap_ligands(imol_new, imol, chain_id, res_no) - match_ligand_torsions(imol_new, imol, chain_id, res_no) # broken? - overlap_ligands(imol_new, imol, chain_id, res_no) - set_residue_name(imol_new, "", 1, "", rn) - change_chain_id(imol_new, "", chain_id, 1, 1, 1) - renumber_residue_range(imol_new, chain_id, 1, 1, res_no - 1) - set_mol_displayed(imol_new, 0) - set_mol_active (imol_new, 0) - #set_mol_displayed(imol, 0) - #set_mol_active (imol, 0) - - # I don't think that replace-fragment is the right - # function because that does not copy across the hydrogen - # atoms - and we want those, probably - - #replace_fragment(imol, imol_new, - # "//" + chain_id + "/" + str(res_no)) - - imol_replacing = add_ligand_delete_residue_copy_molecule( - imol_new, chain_id, res_no, imol, chain_id, res_no) - col = get_molecule_bonds_colour_map_rotation(imol) - new_col = col + 5 - set_molecule_bonds_colour_map_rotation(imol_replacing, new_col) - set_mol_displayed(imol_replacing, 0) - set_mol_active (imol_replacing, 0) - graphics_draw() - - -# ---------- annotations --------------------- - -def add_annotation_here(text): - global annotations - rc = rotation_centre() - ann = [text] + rc - - annotations.append(ann) - place_text(*(ann + [0])) - graphics_draw() - -def add_annotation_at_click(text): - global pass_text - pass_text = text - def add_here(*args): - global annotations - global pass_text - text = pass_text - # atom_specs for user_defined_clicks have 7 args! - # includes model number now too! - # maybe there should be a atom_spec including model no!? - atom_spec = atom_specs(*args[0][1:7]) - ann = [text] + atom_spec[3:] - annotations.append(ann) - place_text(*(ann + [0])) - graphics_draw() - user_defined_click(1, add_here) - -def save_annotations(file_name): - global annotations - #if (os.path.isfile(file_name)): - # remove existing file - # print "BL INFO:: overwrite old annotation file", file_name - # os.remove(file_name) - - save_string_to_file(str(annotations), file_name, True) - -def load_annotations(file_name): - if (os.path.isfile(file_name)): - from types import ListType - port = open(file_name, 'r') - ls = port.readline() - port.close() - ls = ls.rstrip("\n") - ls = eval(ls) - if (type(ls) is ListType): - global annotations - annotations = ls - for ann in annotations: - place_text(*(ann + [0])) - graphics_draw() - - -# ---------- updating --------------------- - -global pending_install_in_place -pending_install_in_place = False -# shall this be global? Currently pass use_curl along? FIXME -#global use_curl -#use_curl = False - -# Here we construct the url that contains the latest (pre) -# release info adding in "pre-release" if this binary is a -# pre-release. -# args ends up as something like: -# ["xxx/phone_home.py", "pre-release" -# "binary", "Linux-1386-fedora-10-python-gtk2" -# "command-line", "/home/xx/coot/bin/coot"] -# -def make_latest_version_url(): - build_type = coot_sys_build_type() - # FIXME this is only for biop files !!! - # what about versions in York? - host = "http://www.biop.ox.ac.uk/coot/software/binaries/" - pre_dir = "pre-releases" if pre_release_qm() else "releases" - if is_windows(): - host = "http://www.ysbl.york.ac.uk/~lohkamp/software/binaries/" - pre_dir = "nightlies/pre-release" if pre_release_qm() else "stable" - url = host + \ - pre_dir + \ - "/" + \ - "type-binary-" + \ - build_type + \ - "-latest.txt" - return url - - - -# Get the binary (i.e. the action that happens when the download -# button is pressed). This is run in a thread, so it cant do -# any graphics stuff (except for updating the progress bar when -# passed). -# -# return True if tar file was successfully downloaded and untared -# and False if not. -# -# This is using python/urllib by default, set use_curl to True to use curl -# -def run_download_binary_curl(revision, version_string, - pending_install_in_place_func, - set_file_name_func=False, # combine with progress_bar?! - progress_bar=False, - use_curl=False): - - global pending_install_in_place - - def match_md5sums(tar_file_name, target_md5sum_file_name): - # necessary to check for files? done already above? - if not os.path.isfile(tar_file_name): - return False - else: - if not os.path.isfile(target_md5sum_file_name): - #print "OOps! %s does not exist" %target_md5sum_file_name - print "OOps! {0!s} does not exist".format(target_md5sum_file_name) - return False - else: - target_md5_string = get_target_md5_string(target_md5sum_file_name) - # remove the md5sum file (not needed any more) - os.remove(target_md5sum_file_name) - md5_string = get_md5sum_string(tar_file_name) - if not target_md5_string: # need to test if string? - #print "OOps %s is not a string" %target_md5_string - print "OOps {0!s} is not a string".format(target_md5_string) - return False - else: - if not md5_string: # as above - #print "OOps %s is not a string" %md5_string - print "OOps {0!s} is not a string".format(md5_string) - return False - else: - if not (target_md5_string == md5_string): - #print "Oops: md5sums do not match %s %s. Doing nothing" \ - # %(target_md5_string, md5_string) - print "Oops: md5sums do not match {0!s} {1!s}. Doing nothing".format(target_md5_string, md5_string) - return False - else: - return True - - # return success status as a boolean - # use_tar, use 'tar' function or pythonic tarfile function - # - def install_coot_tar_file(tar_file_name, use_tar = False): - prefix_dir = os.getenv("COOT_PREFIX") - prefix_dir = os.path.normpath(prefix_dir) # FIXME do we need this? - if not prefix_dir: - #print "OOps could not get COOT_PREFIX" - return False - if not directory_is_modifiable_qm(prefix_dir): - #print "OOps directory %s is not modifiable" %prefix_dir - return False - else: - pending_dir = os.path.join(prefix_dir, "pending-install") - if not os.path.isdir(pending_dir): - os.mkdir(pending_dir) - if not os.path.isdir(pending_dir): - #print "OOps could not create", pending_dir - return False - else: - a_tar_file_name = os.path.abspath(tar_file_name) - # with working dir !? - current_dir = os.getcwd() - os.chdir(pending_dir) - print "now current dir is", os.getcwd() - if use_tar: - # non-pythonic - popen_command("tar", ["xzf", a_tar_file_name], [], - "untar.log", False) - else: - # pythonic - if not is_windows(): - import tarfile - tar = tarfile.open(a_tar_file_name) - tar.extractall() - tar.close() - else: - if os.path.isfile(tar_file_name): - # needs to be removed on WIN32 first - os.remove(tar_file_name) - os.rename(a_tar_file_name, tar_file_name) - - os.chdir(current_dir) - return True # ? - - - # return as a string, or False - def get_target_md5_string(file_name): - if not os.path.isfile(file_name): - return False - else: - fin = open(file_name, 'r') - lines = fin.readlines() - fin.close() - first_line = lines[0] - return first_line[0:first_line.find(" ")] - - # return a string - def get_md5sum_string(file_name): - if not os.path.isfile(file_name): - return False - else: - import hashlib - fin = open(file_name, 'rb') - md5sum = hashlib.md5(fin.read()).hexdigest() - fin.close() - return md5sum - - - # main line - # - #print "::::: run_download_binary_curl.... with revision %s with version_string %s" \ - # %(revision, version_string) - prefix = os.getenv("COOT_PREFIX") - prefix = os.path.normpath(prefix) # FIXME do we need this? - if not prefix: # do we need to check if prefix is string? - print "OOps! Can't find COOT_PREFIX" - return False - else: - pre_release_flag = "-pre" in coot_version() - ys = "www.ysbl.york.ac.uk/~emsley/software/binaries/" - binary_type = coot_sys_build_type() - type_list = ['Linux-i386-fedora-3', 'Linux-i386-fedora-3-python', 'Linux-i386-fedora-8-python-gtk2', - 'Linux-i386-fedora-8-gtk2', 'Linux-i386-fedora-10-python-gtk2', 'Linux-i386-fedora-10-gtk2', - 'Linux-i686-ubuntu-8.04.3', 'Linux-i686-ubuntu-8.04.3-python'] - if binary_type in type_list: - host_dir = ys - else: - host_dir = "www.biop.ox.ac.uk/coot/software/binaries/" - - if is_windows(): - host_dir = "www.ysbl.york.ac.uk/~lohkamp/software/binaries/" - - tar_file_name = version_string - if is_windows(): - tar_file_name += ".exe" - else: - tar_file_name += "-binary-" + binary_type + ".tar.gz" - - release_dir = "releases/" - if ("ysbl.york.ac.uk" in host_dir): # includes windows - if pre_release_flag: - release_dir = "nightlies/pre-release/" - else: - release_dir = "stable/" - else: - if pre_release_flag: - release_dir = "pre-releases/" - else: - release_dir = "releases/" - - url = "http://" + host_dir + release_dir + tar_file_name - md5_url = url + ".md5sum" - md5_tar_file_name = tar_file_name +".md5sum" - - #print "md5sum url for curl:", md5_url - #print "url for curl:", url - - if set_file_name_func: - set_file_name_func(tar_file_name) - - print "INFO:: getting URL:", url - - if (use_curl): - # this is for curl - coot_get_url_and_activate_curl_hook(md5_url, md5_tar_file_name, 1) - coot_get_url_and_activate_curl_hook(url, tar_file_name, 1) - - if pending_install_in_place: - return False - else: - pending_install_in_place = "full" - - else: - # this is for pythonic urllib - # we have graphics here, grrrr, shouldnt - import urllib - def progress_function(count, blockSize, totalSize): - global pending_install_in_place - percent = int(count*blockSize*100/totalSize) - dots = int(percent / 2.5) * "=" - if percent < 100: - dots += ">" - sys.stdout.write("\rProgress {0:d}%".format(percent) + " |{0:<40!s}|".format(dots)) - sys.stdout.flush() - if progress_bar: - progress_bar.set_text("Downloading {0!s} %".format(percent)) - progress_bar.set_fraction(percent/100.) - if (pending_install_in_place == "cancelled"): - # Brute force exit of thread! - sys.stdout.write("\nBL INFO:: stopping download\n") - sys.stdout.flush() - sys.exit() - - try: - md5_url_local_file_name, md5_url_info = urllib.urlretrieve(md5_url, md5_tar_file_name) - except: - print "BL ERROR:: could not download", md5_url - return False - try: - print "\n" - print "Downloading: {0!s}".format(tar_file_name) - url_local_file_name, url_info = urllib.urlretrieve(url, tar_file_name, progress_function) - pending_install_in_place = "full" - print "\nDone" - except: - if not (pending_install_in_place == "cancelled"): - print "BL ERROR:: could not download", url - return False - - if not os.path.isfile(tar_file_name): - #print "Ooops: %s does not exist after attempted download" %tar_file_name - return False - else: - if not os.path.isfile(md5_tar_file_name): - #print "Ooops: %s does not exist after attempted download" %md5_tar_file_name - return False - else: - if not match_md5sums(tar_file_name, md5_tar_file_name): - return False - else: - success = install_coot_tar_file(tar_file_name) - if success: - pending_install_in_place_func = True - return True - return False - -# get revision number from string -# -# (used in downloading new version) -# -def get_revision_from_string(stri): - # e.g. str is "coot-0.6-pre-1-revision-2060" (with a newline at the - # end too). We want to return 2060 (a number) from here (or False). - if stri: # maybe test for string - lss = stri.rsplit("\n") - ls = lss[0].split("-") - try: - return int(ls[-1]) - except: - return False - return False - -# for true pythonic url retrievel -# returns url as string or False if error -# -def get_url_as_string(my_url): - - import urllib - try: - s = urllib.urlopen(my_url).read() - except: - s = False # not sure if that's the right way - return s - - -# first generate a version string with no trailing newline. -# actually removes last char (\n) and everything before c/W. -# -# e.g. input: "coot-0.6.2-pre-1-revision-2765\n" -# output: "coot-0.6.2-pre-1-revision-2765" -# -def coot_split_version_string(stri): - if not is_windows(): - ls2 = stri[stri.find("c"):-1] # for 'coot' start - else: - ls2 = stri[stri.find("W"):-1] # for 'WinCoot' start - return ls2 - -# convert file to string -def file2string(file_name): - if not os.path.isfile(file_name): - return False - else: - fin = open(file_name) - ret = fin.read() - fin.close() - return ret - -# If "default.seq" (a simple text file with the sequence (not PIR or -# FASTA)) exists in the current directory, then try to assign it to -# each chain of each molecule. -# -# In the first case the sequence is assigned to the closest match -# (model sequence to target sequence), subsequently only chains -# without a sequence associated with them are candidates for -# matching. The protein sequence has to have at least 95% sequence -# identity with the target sequence in "default.seq" -# -def load_default_sequence(): - - default_seq = "default.seq" - if os.path.isfile(default_seq): - s = file2string(default_seq) - align_to_closest_chain(s, 0.95) - - -# not sure if this works, especally with python and Win -# is for command line update -# FIXME - -# update self -# -# keep a copy of the old directories around in a directory named -# after expiration time. -# -def update_self(use_curl=False): - import operator - import time - global file_name_for_progress_bar - file_name_for_progress_bar = False - - url = make_latest_version_url() - if use_curl: - #x=get_url_as_string(url) # dummy to fool the firewall FIXME - coot_url = coot_get_url_as_string(url) - else: - coot_url = get_url_as_string(url) - if not coot_url: - print "BL INFO:: could not get string from URL {0!s}, so no update".format(url) - else: - version_string = coot_split_version_string(coot_url) - revision = get_revision_from_string(version_string) - global pending_install_in_place - pending_install_in_place = False - - def set_file_name_func(file_name): - global file_name_for_progress_bar - file_name_for_progress_bar = file_name - - def pending_install_in_place_func(val): - global pending_install_in_place - pending_install_in_place = val - - global continue_status - continue_status = True - def threaded_func(): - ret = run_download_binary_curl(revision, version_string, - pending_install_in_place_func, - set_file_name_func, - use_curl=use_curl) - global continue_status - continue_status = False - - run_python_thread(threaded_func, []) - # how about a time out? - count = 0 - while continue_status: - if file_name_for_progress_bar: - curl_info = curl_progress_info(file_name_for_progress_bar) - if curl_info: - v1 = curl_info['content-length-download'] - v2 = curl_info['size-download'] - if operator.isNumberType(v1): - if operator.isNumberType(v2): - f = v2 / v1 - #sys.stdout.write("\rProgress %3.2f%%" %(f*100)) - #sys.stdout.flush() - print "{0:3.2f}%".format((f*100)) - if f > 0.999: - continue_status = False - elif count >= 1500: # about 50 min - continue_status = False - else: - count += 1 - time.sleep(2) - coot_real_exit(0) - - -def use_curl_status(): - global use_curl - return use_curl - -def set_use_curl(status): - global use_curl - use_curl = status - - -# Invert the chiral centre of the atom we are centred on. -# If not centred on a chiral atom, then give a dialog. -# -# The restraints for this monomer type are copied and renamed -# (changing comp-id, 3-letter-code and name too). The monomer is -# regularized. Chiral Hydrogen (if needed) is enabled now in the -# minimizer. -# -# This should almost all be c++ code so that Bernie doesn't have to -# redo it. This is temporary then -def chiral_centre_inverter(): - # just to do something. Wait until this is in c++ code... - info_dialog("BL waiting for PE to put in C++ code.\n") - return False - -def residue_is_close_to_screen_centre_qm(imol, chain_id, res_no, ins_code): - def square(x): return x * x - rc = residue_centre(imol, chain_id, res_no, ins_code) - if not isinstance(rc, types.ListType): - return False - else: - sc = rotation_centre() - dist_sum_sq = sum(square(rcx-scx) for rcx, scx in zip(rc, sc)) - return dist_sum_sq < 25. - -# return a string "DB00xxxx.mol" or some such - this is the file name -# of the mdl mol file from drugbank. Or False/undefined on fail. -# Test result with string?. -# -def get_drug_via_wikipedia(drug_name_in): - - - import urllib2 - from xml.etree import ElementTree - - def get_redirected_drug_name(xml): - return parse_wiki_drug_xml(xml, '#REDIRECT', True) - - def parse_wiki_drug_xml(tree, key, redirect=False): - key_re = re.compile(key) - drug_bank_id = False - query_ele = tree.find("query") - rev_iter = query_ele.getiterator("rev") - if len(rev_iter) > 0: - rev_text = rev_iter[0].text - # seems to be in some strange format!? - decode_text = rev_text.encode('ascii', 'ignore') - for line in decode_text.split("\n"): - # if key in line: # too simple, we need a regular expresssion search - if key_re.search(line): - if (redirect == False): - drug_bank_id = line.split(" ")[-1] - if not drug_bank_id: - # we can get an empty string - drug_bank_id = False - else: - # a REDIRECT was found - drug_bank_id = line[line.find("[[")+2:line.find("]]")] - else: - print 'Oops! len rev_text is 0' - - return drug_bank_id - - - file_name = False - if isinstance(drug_name_in, str): - if len(drug_name_in) > 0: - drug_name = drug_name_in.lower() - url = "http://en.wikipedia.org/w/api.php?format=xml&action=query&titles=" + \ - drug_name + \ - "&prop=revisions&rvprop=content" - - # we want to parse the Etree rather than xml as this is an addurlinfo thingy - xml = urllib2.urlopen(url) - xml_tree = ElementTree.parse(xml) - - mol_name = parse_wiki_drug_xml(xml_tree, "DrugBank *= ") - - if not isinstance(mol_name, str): - print "BL WARNING:: mol_name not a string (DrugBank entry from wikipedia)", mol_name - # try pubchem as fallback - mol_name = parse_wiki_drug_xml(xml_tree, "PubChem *= ") - if not isinstance(mol_name, str): - - print "BL WARNING:: mol_name not a string (pubchem entry either)", mol_name - # so was there a redirect? - # if so, get the name and call get_drug_via_wikipedia with it - redirected_drug_name = get_redirected_drug_name(xml_tree) - return get_drug_via_wikipedia(redirected_drug_name) - - else: - pc_mol_uri = "http://pubchem.ncbi.nlm.nih.gov" + \ - "/summary/summary.cgi?cid=" + \ - mol_name + "&disopt=DisplaySDF" - file_name = "pc-" + mol_name + ".mol" - coot_get_url(pc_mol_uri, file_name) - - else: - db_mol_uri = "http://www.drugbank.ca/structures/structures/small_molecule_drugs/" + \ - mol_name + ".mol" - file_name = mol_name + ".mol" - coot_get_url(db_mol_uri, file_name) - return file_name - - -def get_SMILES_for_comp_id_from_pdbe(comp_id): - - if not isinstance(comp_id, str): - return False - else: - s = SMILES_for_comp_id(comp_id) - if isinstance(s, str): - return s - else: - cif_file_name = os.path.join("coot-download", - "PDBe-" + comp_id + ".cif") - url = "ftp://ftp.ebi.ac.uk/pub/databases/msd/pdbechem/files/mmcif/" + \ - comp_id + \ - ".cif" - make_directory_maybe("coot-download") - if os.path.isfile(cif_file_name): - # try the filesystem cache - l = os.stat(cif_file_name).st_size - if (l > 0): - read_cif_dictionary(cif_file_name) - s2 = SMILES_for_comp_id(comp_id) - if isinstance(s2, str): - return s2 - else: - # give a dialog, saying that the file will not be - # overwritten - msg = cif_file_name + \ - " exists but is empty." + \ - "\nNot overwriting." - info_dialog(msg) - return False - # use network then - print "BL INFO:: getting url:", url - state = coot_get_url(url, cif_file_name) - if (state != 0): - msg = "Problem downloading\n" + \ - url + "\n to file \n" + \ - cif_file_name + \ - "." - info_dialog(msg) - return False - else: - read_cif_dictionary(cif_file_name) - s = SMILES_for_comp_id(comp_id) - if isinstance(s, str): - return s - # something probably went wrong if we got to here - return False - -# # load the redefining functions -# try: -# load_from_search_load_path("redefine_functions.py") -# # import redefine_functions -# except: -# print "load_from_search_load_path() of redefine_functions.py failed" -# pass - -# Add file with filename to preferences directory -# -def file_to_preferences(filename): - - """Copy the file filename from python pkgdatadir directory to - prefereneces directory. - """ - - import shutil - - # depending on where/how Coot was build pkgdatadir may not be available - # or point the wrong way - pgkdata_dir = get_pkgdatadir() - if os.path.isdir(pkgdatadir): - ref_py = os.path.join(pkgdatadir, "python", filename) - else: - # dont have accessible pkgdata_dir, so guess install place - python_dir = os.getenv("COOT_PYTHON_DIR") - if os.path.isdir(python_dir): - ref_py = os.path.join(python_dir, "python", filename) - if not os.path.exists(ref_py): - add_status_bar_text("Missing reference template key bindings.") - else: - # happy path - home = os.getenv("HOME") - if is_windows(): - home = os.getenv("COOT_HOME") - if isinstance(home, str): - pref_dir = os.path.join(home, ".coot-preferences") - if not os.path.isdir(pref_dir): - make_directory_maybe(pref_dir) - pref_file = os.path.join(pref_dir, filename) - # don't install it if it is already in place. - if os.path.isfile(pref_file): - s = "keybinding file " + pref_file + \ - " already exists. Not overwritten." - add_status_bar_text(s) - else: - shutil.copyfile(ref_py, pref_file) - if os.path.isfile(pref_file): - execfile(pref_file, globals()) - -# add terminal residue is the normal thing we do with an aligned -# sequence, but also we can try ton find the residue type of a -# residue in the middle of the chain that is modelled as an ALA, say. -# -# PE comment - not sure why needed. -#find_aligned_residue_type = find_terminal_residue_type - -def using_gui(): - # we shall see if coot_main_menubar is defined in guile or python - ret = False - if coot_has_guile(): - ret = run_scheme_command("(defined? 'coot-main-menubar)") - if not ret: - ret = globals().has_key("coot_python") # coot_main_menubar is not a global var - return ret - -############################################################################################ -# end of Paul's scripting -############################################################################################ -# -# some BL functions -# -############################################################################################ -# - -# for easier switching on of GL lighting on surfaces: -# -def GL_light_on(): - set_do_GL_lighting(1) - do_GL_lighting_state() - -# and to turn it off -# -def GL_light_off(): - set_do_GL_lighting(0) - do_GL_lighting_state() - - -# Helper functions to set B-Factors - -# set B-factor to bval for molecule imol -# -def set_b_factor_molecule(imol, bval): - - for chain_id in chain_ids(imol): - start_res = seqnum_from_serial_number(imol, chain_id, 0) - end_res = seqnum_from_serial_number(imol, chain_id, chain_n_residues(chain_id, imol) - 1) - set_b_factor_residue_range(imol, chain_id, start_res, end_res, bval) - -# reset B-factor for molecule imol to default value -# -def reset_b_factor_molecule(imol): - - for chain_id in chain_ids(imol): - start_res = seqnum_from_serial_number(imol, chain_id, 0) - end_res = seqnum_from_serial_number(imol, chain_id, chain_n_residues(chain_id, imol) - 1) - set_b_factor_residue_range(imol, chain_id, start_res, end_res, default_new_atoms_b_factor()) - -# reset B-factor for active residue to default value -# -def reset_b_factor_active_residue(): - - active_atom = active_residue() - - if not active_atom: - print "No active atom" - else: - imol = active_atom[0] - chain_id = active_atom[1] - res_no = active_atom[2] - ins_code = active_atom[3] - atom_name = active_atom[4] - alt_conf = active_atom[5] - - set_b_factor_residue_range(imol, chain_id, res_no, res_no, default_new_atoms_b_factor()) - - -# BL module to find exe files -# we need this for popen as it requires the full path of the exe file -# we use arguments and keyword: -# -# program_name : name of exe to find -# -# args (i.e. path_names) : path name to search (usually "PATH", then maybe CCP4_BIN, ..., -# can be a single path as well) -# kwargs : for some extra argumentsto -# add_extensions=[list] pass extra extensions to be tested -# only_extension=str use only this one to test -# no_disk_search=bool Dont bother searching the disk -# screen_info=bool print info etc in console -# -# then we search everywhere -# -# on OS where "which" is available we use this first, rather than -# searching in PATH etc. -# -# returns full path of exe when successful, False otherwise -# -def find_exe(program_name, *args, **kwargs): - - import os, string - - global search_disk - search_disk = None - info = True - - # we shall check for full path names first - if (os.path.isfile(program_name)): - return os.path.abspath(program_name) - - # if Unix we use which and python's command module to locate the - # executable (indepent if PATH was given); commands only available on - # unix! May use subprocess at some point... - # if the program is not found with which we use the usual way... - if (os.name == 'posix'): - import commands - program_exe = commands.getoutput('which ' + program_name) - if (os.path.isfile(program_exe)): - return program_exe - - if (len(args) > 0): - path_ls = args - else: - # no extra PATH given, should at least check in this dir - # and in PATH - path_ls = ["PATH", os.getcwd()] - - # setting of OS specific path properties - extensions = [] - drives_ls = ["/"] - program_name_noext = program_name - # some windows magic - if (os.name == 'nt'): - drives_ls = get_windows_drives() - program_name_noext = strip_extension(program_name) - file_ext = file_name_extension(program_name) - # if extenion is explicitly given - only use this one - # otherwise try all possible ones on Windows, i.e PATHEXT - if (file_ext): - extensions = [file_ext] - else: - tmp_ext = os.environ["PATHEXT"].split(os.pathsep) - # list of extensions (no dot) only - extensions = map(lambda ext: ext[1:], tmp_ext) - - - if "only_extension" in kwargs: - if kwargs["only_extension"]: - extensions = kwargs["only_extension"] - if "add_extension" in kwargs: - extensions += kwargs["add_extensions"] - if "screen_info" in kwargs: - info = kwargs["screen_info"] - - program_names = [program_name_noext] - if extensions: - program_names = map(lambda ext: program_name_noext + "." + ext, - extensions) - # usually we want to have the one with extension, if there is one - program_names += [program_name_noext] - - for file_name in program_names: - # search the extra Paths - for search_path in path_ls: - - if (os.path.isdir(search_path)): - # we have a single file name, not environ var - program_exe = os.path.join(search_path, file_name) - if (os.path.isfile(program_exe)): - if info: - print "BL INFO:: We found ", program_exe - return program_exe - else: - try: - primary_path = os.environ[search_path] - for path in string.split(primary_path, os.pathsep): - program_exe = os.path.join(path, file_name) - if (os.path.isfile(program_exe)): - if info: - print "BL INFO:: We found ", program_exe - return program_exe - except: - if info: - print "BL WARNING:: {0!s} not defined!".format(search_path) - - # BL says: before we search everywhere we might want to ask - # the user if he actually wishes to do so! - # lets insert a small pygtk dialog and ask! - # only if graphics - if "no_disk_search" in kwargs: - no_search = kwargs["no_disk_search"] - else: - no_search = False - search_disk = False - if (use_gui_qm and not no_search): - search_disk = search_disk_dialog(program_name, path_ls) - if search_disk: - # search everywhere - for drive in drives_ls: - for root, dir, file in os.walk(drive): - program_exe = os.path.join(root, program_name) - if (os.path.isfile(program_exe)): - return program_exe - else: - if info: - print "BL INFO:: we don't search the whole disk for", program_name_noext - - if info: - print "BL WARNING:: We cannot find {0!s} anywhere! Program {1!s} won't run!".format(program_name_noext, program_name_noext) - return False - -# for running online docs -def open_url(url): - import webbrowser - - try: - webbrowser.open(url,1,1) - except: - print "BL WARNING:: Cannot open the URL {0!s} in webbrowser {1!s}!".format(url, webbrowser.get()) - - -# to reload modules -def reload_module(name): - import os - path = os.getenv('COOT_PYTHON_DIR') - file = os.path.join(path, name) - execfile(file) - -# to make print a function: -def printf(*args): - for arg in args: - print arg, - -# to print elements of a list: -def printl(ls): - map(printf, ls) - -# Where cmd is e.g. "bltwish" -# args is list, e.g. [loggraph, "refmac.log"] -# -# in python < 2.4 (and if no logfile) -# -# Returns the pid or False if failed. -# -# in python >= 2.4 (and with logfile) -# -# Returns the process and the open log file object -# -# uses os.spawn if python version < 2.4 otherwise subprocess -# -def run_concurrently(cmd, args=None, data_list=None, logfile=None, screen_flag=False): - if args is None: - args = [] - import sys, string, os - - major, minor, micro, releaselevel, serial = sys.version_info - - cmd_execfile = "" - if not(command_in_path_qm(cmd)): - print "command ", cmd, " not found in $PATH!" - print "BL INFO:: Maybe we'll find it somewhere else later..." - else: - cmd_execfile = find_exe(cmd,"CCP4_BIN","PATH") - - if (cmd_execfile): - if (major >= 2 and minor >=4): - # subprocess - import subprocess - cmd_args = [cmd_execfile] + args - log = logfile - if (logfile): - log = open(logfile, 'w') - process = subprocess.Popen(cmd_args, stdin=subprocess.PIPE, stdout=log) - - if (data_list): - for data in data_list: - process.stdin.write(data + "\n") - - pid = process.pid - - if log: - return (process, log) - else: - return pid - - else: - # spawn (old) - pid = os.spawnv(os.P_NOWAIT, cmd_execfile, [cmd_execfile] + args) - return pid - else: - print "WARNING:: could not find {0!s}, so not running this program".format(cmd) - return False - -# python command to see if we have pygtk available -# return True if availabel otherwise False -# -def coot_has_pygtk(): - import sys - if ('pygtk' in sys.modules.keys()): - return True - else: - return False - -# python command to see if we have pygobject available -# return True if availabel otherwise False -# -def coot_has_gobject(): - import sys - if ('gobject' in sys.modules.keys()): - return True - else: - return False - - -# function to kill a process, given the process pid -# return True if managed to kill the process otherwise false -# -def kill_process(pid): - import os - import sys - import signal - - if (os.name == 'nt'): - # Windows killing tasks - try: - # for now use subprocess.call, maybe can use Popen.kill?! - major, minor, micro, releaselevel, serial = sys.version_info - if (major >= 2 and minor >=4): - # new style - import subprocess - ret = subprocess.call("taskkill /F /PID {0:d}".format(pid), shell=True) - else: - ret = os.system("taskkill /F /PID {0:d}".format(pid)) - if (ret == 0): - # success - return True - else: - return False - except: - return False - else: - try: - os.kill(pid, signal.SIGKILL) - return True - except: - return False - - -# some example function for the toolbutton -# maybe should go in coot_gui!? -def stereo_mono_toggle(): - display_state = stereo_mode_state() - if (display_state == 0): - hardware_stereo_mode() - else: - mono_mode() - -def side_by_side_stereo_mono_toggle(): - display_state = stereo_mode_state() - if (display_state == 0): - side_by_side_stereo_mode(0) - else: - mono_mode() - -def zalman_stereo_mono_toggle(): - display_state = stereo_mode_state() - if (display_state == 0): - zalman_stereo_mode() - else: - mono_mode() - -def switch_stereo_sides(): - factor = -1. * hardware_stereo_angle_factor_state() - set_hardware_stereo_angle_factor(factor) - -def toggle_full_screen(widget=None): - """ Toggle between full screen and window mode - - Keyword arguments: - widget -- can be passed from the toolbutton - """ - - if widget: - if widget.get_active(): - # the button is toggled on - full_screen(1) - else: - full_screen(0) - else: - # no alternative for now (could just go by state and change back and forth) - print "BL WARNING:: no widget" - -def split_active_water(): - with UsingActiveAtom() as [aa_imol, aa_chain_id, aa_res_no, aa_ins_code, aa_atom_name, aa_alt_conf]: - split_water(aa_imol, aa_chain_id, aa_res_no, aa_ins_code) - -# helper function to test for a number -# returns True if number, otherwise False -# -def isNumber(num): - """ - helper function to test for a number - returns True if number, otherwise False - """ - if (isinstance(num, int) or isinstance(num, float)): - return True - else: - return False - - -# function to merge multiple solvent chains -# -def merge_solvent_chains(imol): - - # first renumber all water chains - renumber_waters(imol) - # collect all solvent chains - solvent_chains = [] - for chain_id in chain_ids(imol): - if (is_solvent_chain_qm(imol, chain_id)): - solvent_chains.append(chain_id) - - # now renumber - if (len(solvent_chains) > 1): - master_chain = solvent_chains[0] - last_prev_water = chain_n_residues(master_chain, imol) - for chain_id in solvent_chains[1:]: - n_residues = chain_n_residues(chain_id, imol) - renumber_residue_range(imol, chain_id, 1, - n_residues, last_prev_water) - new_start = last_prev_water + 1 - new_end = last_prev_water + n_residues - change_chain_id(imol, chain_id, master_chain, 1, - new_start, new_end) - last_prev_water = new_end - - -# helper to comvert functions to strings -def cmd2str(*args): - from types import StringType - func = args[0] - if callable(func): - ret = args[0].__name__ - else: - ret = str(func) - ret += "(" - for arg in args[1:]: - if type(arg) is StringType: - ret += "\"" + arg + "\"" - else: - ret += str(arg) - if not arg == args[-1]: - ret += ", " - ret += ")" - return ret - - -# Function to change the occupancies of alternative conformations -# alt_conf_list is a list of alt_conf string and occ, -# e.g. [["A", 0.8], ["B", 0.2]] -# -def set_alt_conf_occ(imol, chain_id, res_no, ins_code, alt_conf_list): - """ - Function to change the occupancies of alternative conformations - alt_conf_list is a list of alt_conf string and occ, - e.g. [["A", 0.8], ["B", 0.2]] - """ - # first check if we have alt confs: - alt_confs = residue_alt_confs(imol, chain_id, res_no, ins_code) - if (alt_confs > 1): - atom_ls = residue_info(imol, chain_id, res_no, ins_code) - change_list = [] - for i in range(len(atom_ls)): - alt_conf_str = atom_ls[i][0][1] - atom_name = atom_ls[i][0][0] - for (alt_conf_name, alt_conf_occ) in alt_conf_list: - if (alt_conf_str == alt_conf_name): - change_list.append([imol, chain_id, res_no, ins_code, atom_name, - alt_conf_str, "occ", alt_conf_occ]) - set_atom_attributes(change_list) - else: - print "BL INFO:: no alt confs in residue", imol, chain_id, res_no, ins_code - - -# simplyfy check for windows -def is_windows(): - return os.name == 'nt' - -# find all windows drives -# -def get_windows_drives(): - from ctypes import windll - drives = [] - bitmask = windll.kernel32.GetLogicalDrives() - for letter in string.uppercase: - if bitmask & 1: - drives.append(letter + ":\\") - bitmask >>= 1 - - return drives - - -# clean up pdb file (imol) -# a wrapper for fix_nomenclature errors, sort chains, residues, merge -# solvent chains, renumber waters, etc. -# -def clean_pdb(imol): - - """clean up pdb file (imol) - a wrapper for fix_nomenclature errors, sort chains, residues, merge - solvent chains, renumber waters, etc.""" - - fix_nomenclature_errors(imol) - merge_solvent_chains(imol) - renumber_waters(imol) - sort_chains(imol) - sort_residues(imol) - -# acronym -merge_water_chains = merge_solvent_chains - -# the python run_thread function if no graphics -#global use_gui_qm -#if not use_gui_qm: -# import threading -# # this has locked, so that no one else can use it -# global python_thread_return -# python_thread_return = False -# -# # function to run a python thread with function using -# # args which is a tuple -# # optionally pass sleep time in ms (default is 20) - usefull -# # for computationally expensive threads which may have run longer -# # N.B. requires gobject hence in coot_gui.py -# # -# def run_python_thread(function, args): -# -# class MyThread(threading.Thread): -# def __init__(self): -# threading.Thread.__init__(self) -# def run(self): -# global python_thread_return -# python_return_lock = threading.Lock() -# python_return_lock.acquire() -# try: -# python_thread_return = function(*args) -# finally: -# python_return_lock.release() -# -# MyThread().start() diff --git a/run_tests b/run_tests deleted file mode 100755 index 5f8ff34f..00000000 --- a/run_tests +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo "Docker is working bro!" diff --git a/setup-scripts/pandda.setup-sh b/setup-scripts/pandda.setup-sh deleted file mode 100755 index c2844986..00000000 --- a/setup-scripts/pandda.setup-sh +++ /dev/null @@ -1,3 +0,0 @@ -# module load pymol -module load buster -source /dls/science/groups/i04-1/software/pandda_0.2.12/ccp4/ccp4-7.0/bin/ccp4.setup-sh diff --git a/setup-scripts/xce.setup-csh b/setup-scripts/xce.setup-csh deleted file mode 100755 index 22eca627..00000000 --- a/setup-scripts/xce.setup-csh +++ /dev/null @@ -1,2 +0,0 @@ -unsetenv PYTHONPATH - diff --git a/setup-scripts/xce.setup-sh b/setup-scripts/xce.setup-sh deleted file mode 100755 index 75477e49..00000000 --- a/setup-scripts/xce.setup-sh +++ /dev/null @@ -1,12 +0,0 @@ -unset PYTHONPATH - -# --- DLS specific settings --- -for dir in /* - do - if [ $dir = "/dls" ]; then - module load global/cluster - module load phenix - module load coot - module load buster - fi - done; diff --git a/setup.cfg b/setup.cfg new file mode 100755 index 00000000..9f15817e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[flake8] +# Make flake8 respect black's line length (default 88), +max-line-length = 88 +extend-ignore = + E203, # See https://github.com/PyCQA/pycodestyle/issues/373 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100755 index 00000000..29826470 --- /dev/null +++ b/setup.py @@ -0,0 +1,10 @@ +from setuptools import find_packages, setup + +setup( + name="xce", + version="2.0.1", + description="GUI tool for XChem", + author="Tobias Krojer", + packages=find_packages(), + install_requires=[], +) diff --git a/setupssh.sh b/setupssh.sh deleted file mode 100755 index ab8f0438..00000000 --- a/setupssh.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -echo "Please enter your fedID:" -echo " " -read fedid -echo "Now generating ssh key..." -echo " " -rm ~/.ssh/* -ssh-keygen -t rsa -ssh-copy-id $fedid@nx.diamond.ac.uk - - -echo "Please enter the full path to the directory where you want to mount the diamond file system:" -echo " " - -read mountdir - -string="sshfs -o Ciphers=arcfour -o Compression=no -o allow_other -o reconnect -o workaround=rename ${fedid}@nx.diamond.ac.uk:/dls/labxchem/data ${mountdir}" - -echo $string > mount_diamond.sh - -string2="cd ${mountdir}" - -echo $string2 >> mount_diamond.sh diff --git a/test_build.sh b/test_build.sh deleted file mode 100755 index 6eabb450..00000000 --- a/test_build.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if [[ "$OSTYPE" == "linux-gnu" ]]; then - wget http://devtools.fg.oisin.rc-harwell.ac.uk/nightly/ccp4-linux64-latest.tar.bz2 - bunzip2 ccp4-linux64-latest.tar.bz2 - mkdir ./ccp4 - tar -xf ccp4-linux64-latest.tar -C ./ccp4 --strip-components=1 -elif [[ "$OSTYPE" == "darwin"* ]]; then - wget http://devtools.fg.oisin.rc-harwell.ac.uk/nightly/ccp4-osx-clang-latest.tar.gz - gunzip ccp4-osx-clang-latest.tar.gz - mkdir ./ccp4 - tar -xf ccp4-osx-clang-latest.tar -C ./ccp4 --strip-components=1 -fi -cd ccp4 -echo "changed directory to ccp4" -echo "running setup" -yes y | ./BINARY.setup > /dev/null 2>&1 -echo "finishing some other stuff..." -source bin/ccp4.setup-sh -yes y | ccp4-python -m pip uninstall panddas -ccp4-python -m pip install panddas -#git clone https://www.github.com/xchem/XChemExplorer diff --git a/web/XChemWeb.py b/web/XChemWeb.py deleted file mode 100755 index d80e23b0..00000000 --- a/web/XChemWeb.py +++ /dev/null @@ -1,405 +0,0 @@ -# last edited: 05/07/2017, 15:00 - -import os,sys -import glob - -sys.path.append(os.getenv('XChemExplorer_DIR')+'/lib') -import XChemLog -import XChemDB -import XChemMain - -from XChemUtils import pdbtools -from XChemUtils import mtztools - - -class export_to_html: - - def __init__(self,htmlDir,projectDir,database,xce_logfile): - self.htmlDir = htmlDir - self.projectDir = projectDir - self.Logfile=XChemLog.updateLog(xce_logfile) - self.db=XChemDB.data_source(database) - self.db_dict = None - self.pdb = None - self.protein_name = None - - def prepare(self): - self.Logfile.insert('======== preparing HTML summary ========') - self.makeFolders() - self.copy_jscss() - html = XChemMain.html_header() - firstFile = True - for xtal in self.db.samples_for_html_summary(): - self.db_dict = self.db.get_db_dict_for_sample(xtal) - if firstFile: - if self.db_dict['ProteinName'] == 'None': - self.Logfile.warning('could not determine protein name') - try: - self.protein_name = xtal.split('-')[0] - self.Logfile.warning('xtal name = %s => setting protein name to %s' %(xtal,self.protein_name)) - except IndexError: - self.Logfile.warning('could not determine protein name from cystal name; setting to None') - self.protein_name = '' - else: - self.protein_name = self.db_dict['ProteinName'] - self.Logfile.insert('protein name is: ' + self.protein_name) - self.copy_pdb(xtal) - self.copy_mtz(xtal) -# self.copy_electron_density(xtal) - self.copy_ligand_files(xtal) - for ligand in self.ligands_in_pdbFile(xtal): - ligName = ligand.split('-')[0] - ligChain = ligand.split('-')[1] - ligNumber = ligand.split('-')[2] - eventMap = self.find_matching_event_map_from_database(xtal, ligand) - if eventMap: - self.cut_and_copy_map(xtal, ligand+'.pdb', eventMap, xtal + '_' + ligand + '_event.ccp4','F','PHIF') - x,y,z = self.pdb.get_centre_of_gravity_of_residue(ligand) - self.copy_spider_plot(xtal,ligand) - pdbID = self.db_dict['Deposition_PDB_ID'] - compoundImage = xtal + '_' + self.db_dict['CompoundCode'] + '.png' - compoundCIF = xtal + '_' + self.db_dict['CompoundCode'] + '.cif' - residuePlot = xtal + '_' + ligand + '.png' - pdb = xtal + '.pdb' - event = xtal + '_' + ligand + '_event.ccp4' - thumbNail = xtal + '_' + ligand + '_thumb.png' - resoHigh = self.db_dict['DataProcessingResolutionHigh'] - spg = self.db_dict['RefinementSpaceGroup'] - unitCell = self.db_dict['DataProcessingUnitCell'] - os.chdir(os.path.join(self.projectDir,xtal)) - FWT = xtal + '-' + ligand + '_2fofc.ccp4' - self.cut_and_copy_map(xtal, ligand + '.pdb', '2fofc.map', FWT,'FWT','PHWT') - DELFWT = xtal + '-' + ligand + '_fofc.ccp4' - self.cut_and_copy_map(xtal, ligand + '.pdb', 'fofc.map', DELFWT,'DELFWT','PHDELWT') - ligConfidence = self.db.get_ligand_confidence_for_ligand(xtal, ligChain, ligNumber, ligName) - if ligConfidence.startswith('0'): - self.Logfile.warning('%s: ligand confidence of %s-%s-%s is %s; ignoring...' %(xtal,ligChain,ligNumber,ligName,ligConfidence)) - continue - modelStatus = self.db_dict['RefinementOutcome'] - if firstFile: - html += XChemMain.html_ngl(pdb,eventMap.replace(self.projectDir,''),FWT,DELFWT,ligand) - html += XChemMain.html_download(self.protein_name) - html += XChemMain.html_guide() - html += XChemMain.html_table_header() - firstFile = False - - html += XChemMain.html_table_row(xtal,pdbID,ligand,compoundImage,residuePlot,pdb,event, - thumbNail,resoHigh,spg,unitCell,FWT,DELFWT,ligConfidence,modelStatus) - self.make_thumbnail(xtal,x,y,z,ligand,eventMap) - self.prepare_for_download(xtal, pdb, event, compoundCIF, ligand) - self.prepare_zip_archives() -# html = XChemMain.html_download_all_section(html,self.protein_name) - self.write_html_file(html) - self.Logfile.insert('======== finished preparing HTML summary ========') - - - def prepare_zip_archives(self): - os.chdir(os.path.join(self.htmlDir,'files')) - self.Logfile.insert('%s: preparing ZIP archive of all PDB files' %self.protein_name) - os.system('zip %s_allPDBs.zip *.pdb' %self.protein_name) - self.Logfile.insert('%s: preparing ZIP archive of all PanDDA event maps' %self.protein_name) - os.system('zip %s_allEVENTmaps.zip *event.ccp4' %self.protein_name) - self.Logfile.insert('%s: preparing ZIP archive of all CIF files' %self.protein_name) - os.system('zip %s_allCIFs.zip *.cif' %self.protein_name) - self.Logfile.insert('%s: preparing ZIP archive of all MTZ files' %self.protein_name) - os.system('zip %s_allMTZs.zip *.mtz' %self.protein_name) - - - def prepare_for_download(self,xtal,pdb,event,compoundCIF,ligID): - os.chdir(os.path.join(self.htmlDir,'tmp')) - self.Logfile.insert('%s: preparing files for download' %xtal) - zip_in = '' - - if os.path.isfile('../files/%s' %pdb): - os.system('/bin/cp ../files/%s .' %pdb) - zip_in += pdb + ' ' - else: - self.Logfile.error('%s: cannot find %s' %(xtal,pdb)) - - if os.path.isfile('../files/%s' %event): - os.system('/bin/cp ../files/%s .' %event) - zip_in += event + ' ' - else: - self.Logfile.error('%s: cannot find %s' %(xtal,event)) - - if os.path.isfile('../files/%s' %compoundCIF): - os.system('/bin/cp ../files/%s .' %compoundCIF) - zip_in += compoundCIF + ' ' - else: - self.Logfile.error('%s: cannot find %s' %(xtal,compoundCIF)) - - if zip_in != '': - self.Logfile.insert('%s: preparing zip file -> zip %s_%s.zip %s' %(xtal,xtal,ligID,zip_in)) - os.system('zip %s_%s.zip %s' %(xtal,ligID,zip_in)) - os.system('/bin/mv %s_%s.zip ../download' %(xtal,ligID)) - os.system('/bin/rm -f *') - else: - self.Logfile.error('%s: cannot find any input files for creating of zip archive of %s_%s' %(xtal,xtal,ligID)) - - - - def copy_jscss(self): - os.chdir(self.htmlDir) - self.Logfile.insert('copying css and js files to ' + self.htmlDir) - os.system('/bin/cp -r %s/web/jscss/css .' %os.getenv('XChemExplorer_DIR')) - os.system('/bin/cp -r %s/web/jscss/js .' %os.getenv('XChemExplorer_DIR')) - - - def make_thumbnail(self,xtal,x,y,z,ligID,eventMap): - self.Logfile.insert('%s: making thumbnail of for %s and %s' %(xtal,ligID,eventMap)) - sampleDir = os.path.join(self.projectDir,xtal) - os.chdir(sampleDir) - if not os.path.isfile('%s_%s_thumb.png' %(xtal,ligID)): - self.Logfile.insert('%s: preparing thumbnail image of %s' %(xtal,ligID)) - XChemMain.coot_prepare_input(x, y, z, ligID, sampleDir, eventMap) - XChemMain.coot_write_raster_file(ligID,sampleDir) - XChemMain.render_scene(xtal,ligID,sampleDir) - XChemMain.make_thumbnail(xtal, ligID, sampleDir) - if os.path.isfile('%s_%s_thumb.png' %(xtal,ligID)): - self.Logfile.insert('%s: managed to prepare %s_%s_thumb.png' %(xtal,xtal,ligID)) - self.copy_thumbnail(xtal,sampleDir,ligID) - else: - self.Logfile.error('%s: could not generate %s_%s_thumb.png' %(xtal,xtal,ligID)) - - def copy_thumbnail(self,xtal,sampleDir,ligID): - os.chdir(os.path.join(self.htmlDir, 'png')) - self.Logfile.insert('%s: copying %s_%s_thumb.png to html png' %(xtal,xtal,ligID)) - os.system('/bin/cp %s/%s_%s_thumb.png .' %(sampleDir,xtal,ligID)) - - - def makeFolders(self): - self.Logfile.insert('preparing folders in html directory') - os.chdir(self.htmlDir) -# if not os.path.isdir('js'): -# os.mkdir('js') - if not os.path.isdir('tmp'): - os.mkdir('tmp') - if not os.path.isdir('png'): - os.mkdir('png') - if not os.path.isdir('files'): - os.mkdir('files') - if not os.path.isdir('download'): - os.mkdir('download') - - def copy_pdb(self,xtal): - os.chdir(os.path.join(self.htmlDir, 'files')) - self.pdb = None - if os.path.isfile(os.path.join(self.projectDir,xtal,'refine.split.bound-state.pdb')): - self.pdb = pdbtools(os.path.join(self.projectDir,xtal,'refine.split.bound-state.pdb')) - self.Logfile.insert('%s: copying refine.split.bound-state.pdb to html directory' %xtal) - os.system('/bin/cp %s/refine.split.bound-state.pdb %s.pdb' %(os.path.join(self.projectDir,xtal),xtal)) - else: - self.Logfile.error('%s: cannot find refine.split.bound-state.pdb' %xtal) - - def copy_mtz(self,xtal): - os.chdir(os.path.join(self.htmlDir, 'files')) - if os.path.isfile(os.path.join(self.projectDir,xtal,xtal+'.free.mtz')): - self.Logfile.insert('%s: copying %s.free.mtz to html directory' %(xtal,xtal)) - os.system('/bin/cp %s/%s.free.mtz .' %(os.path.join(self.projectDir,xtal),xtal)) - else: - self.Logfile.error('%s: cannot find %s.free.mtz' %(xtal,xtal)) - - def copy_electron_density(self,xtal): - os.chdir(os.path.join(self.htmlDir, 'files')) - - if os.path.isfile(os.path.join(self.projectDir,xtal,'2fofc.map')): - self.Logfile.insert('%s: copying 2fofc.map to html directory' %xtal) - os.system('/bin/cp %s/2fofc.map %s_2fofc.ccp4' %(os.path.join(self.projectDir,xtal),xtal)) - else: - self.Logfile.error('%s: cannot find 2fofc.map' %xtal) - - if os.path.isfile(os.path.join(self.projectDir,xtal,'fofc.map')): - self.Logfile.insert('%s: copying fofc.map to html directory' %xtal) - os.system('/bin/cp %s/fofc.map %s_fofc.ccp4' %(os.path.join(self.projectDir,xtal),xtal)) - else: - self.Logfile.error('%s: cannot find fofc.map' %xtal) - - def copy_ligand_files(self,xtal): - os.chdir(os.path.join(self.htmlDir,'files')) - - if os.path.isfile(os.path.join(self.projectDir,xtal,self.db_dict['CompoundCode']+'.cif')): - self.Logfile.insert('%s: copying compound cif file' %xtal) - os.system('/bin/cp %s %s_%s' %(os.path.join(self.projectDir,xtal,self.db_dict['CompoundCode']+'.cif'),xtal,self.db_dict['CompoundCode']+'.cif')) - else: - self.Logfile.error('%s: cannot find compound cif file -> %s' %(xtal,self.db_dict['CompoundCode']+'.cif')) - - os.chdir(os.path.join(self.htmlDir,'png')) - - if os.path.isfile(os.path.join(self.projectDir,xtal,self.db_dict['CompoundCode']+'.png')): - self.Logfile.insert('%s: copying compound png file' %xtal) - os.system('/bin/cp %s %s_%s' %(os.path.join(self.projectDir,xtal,self.db_dict['CompoundCode']+'.png'),xtal,self.db_dict['CompoundCode']+'.png')) - else: - self.Logfile.error('%s: cannot find compound png file -> %s' %(xtal,self.db_dict['CompoundCode']+'.png')) - - def copy_spider_plot(self,xtal,ligID): - os.chdir(os.path.join(self.htmlDir, 'png')) - refPDB = os.path.join(self.projectDir,xtal,'refine.pdb') - self.Logfile.insert('%s: looking for spider plots...' %xtal) - if os.path.isfile(refPDB): - refPDBreal = os.path.realpath(refPDB)[:os.path.realpath(refPDB).rfind('/')] - plot = os.path.join(refPDBreal,'residue_plots',ligID.replace('LIG-','')+'.png') - self.Logfile.insert(xtal + ': looking for ' + plot) - if os.path.isfile(plot): - self.Logfile.insert('%s: found %s' % (xtal, plot)) - self.Logfile.insert('%s: copying spider plot for %s' % (xtal, ligID.replace('LIG-', '') + '.png')) - os.system('/bin/cp %s %s_%s.png' % (plot, xtal, ligID)) - else: - self.Logfile.error('%s: cannot find spider plot for %s' %(xtal,ligID.replace('LIG-','')+'.png')) - else: - self.Logfile.error('%s: cannot find refine.pdb, i.e. cannot start looking for spider plots...' %xtal) - - - def ligands_in_pdbFile(self,xtal): - os.chdir(os.path.join(self.projectDir,xtal)) - ligPDB = [] - ligList = [] - self.Logfile.insert('%s: reading ligands to type LIG in refine.split.bound-state.pdb' %xtal) - if os.path.isfile('refine.split.bound-state.pdb'): - ligPDB = self.pdb.save_residues_with_resname(os.path.join(self.projectDir, xtal), 'LIG') - else: - self.Logfile.error('%s: cannot find refine.split.bound-state.pdb' %xtal) - if not ligPDB: - self.Logfile.error('%s; cannot find any ligands of type LIG in refine.split.bound-state.pdb' %xtal) - else: - for lig in sorted(ligPDB): - ligList.append(lig.replace('.pdb', '')) - return ligList - - - def find_matching_event_map_from_database(self,xtal,ligID): - ligName = ligID.split('-')[0] - ligChain = ligID.split('-')[1] - ligNumber = ligID.split('-')[2] - eventMAP = self.db.get_event_map_for_ligand(xtal, ligChain, ligNumber, ligName) - self.Logfile.insert('%s: the database thinks the following event map belongs to %s: %s' %(xtal,ligID,eventMAP)) - print 'event map', eventMAP - if eventMAP == '' or 'none' in str(eventMAP).lower(): - self.Logfile.warning('%s: the respective field in the DB is apparently emtpy' %xtal) - self.Logfile.warning('%s: will try to determine ligand - event map relationship by checking CC...' %xtal) - eventMap = self.find_matching_event_map(xtal,ligID) - elif not os.path.isfile(eventMAP): - self.Logfile.warning('%s: event map file does not exist!' %xtal) - self.Logfile.warning('%s: will try to determine ligand - event map relationship by checking CC...' %xtal) - eventMap = self.find_matching_event_map(xtal,ligID) - else: - self.Logfile.insert('%s: found matching event map!' %xtal) - return eventMAP - - def find_matching_event_map(self,xtal,ligID): - os.chdir(os.path.join(self.projectDir, xtal)) - eventMAP = [] - self.Logfile.insert('%s: trying to find fitting event maps for modelled ligands' %xtal) - if os.path.isfile('no_pandda_analysis_performed'): - self.Logfile.warning('%s: no pandda analysis performed; skipping this step...' %xtal) - return - ligCC = [] - for mtz in sorted(glob.glob('*event*.native*P1.mtz')): - self.get_lig_cc(xtal, mtz, ligID+'.pdb') - cc = self.check_lig_cc(mtz.replace('.mtz', '_CC'+ligID+'.log')) - self.Logfile.insert('%s: %s -> CC = %s for %s' %(xtal,ligID,cc,mtz)) - try: - ligCC.append([mtz,float(cc)]) - except ValueError: - ligCC.append([mtz, 0.00]) - try: - highestCC = max(ligCC, key=lambda x: x[0])[1] - except ValueError: - self.Logfile.error('%s: event maps are not yet converted to mtz files...' %xtal) - return - if highestCC == 0.00 or ligCC is []: - self.Logfile.error('%s: best CC of ligand %s for any event map is 0!' %(xtal,ligID)) - else: - self.Logfile.insert('%s: selected event map -> CC(%s) = %s for %s' %(xtal,ligID,highestCC,mtz[mtz.rfind('/')+1:])) - eventMAP = mtz[mtz.rfind('/')+1:].replace('.P1.mtz','.ccp4') - if not os.path.isfile(eventMAP): - eventMAP = [] -# else: -# self.cut_eventMAP(xtal,ligID,eventMAP) - return eventMAP - - def cut_and_copy_map(self,xtal,pdbCentre,mapin,mapout,F,PHI): - os.chdir(os.path.join(self.projectDir, xtal)) - self.Logfile.insert('%s: cutting density of %s around %s' %(xtal,mapin.replace('.ccp4','.P1.ccp4'),pdbCentre)) - if os.path.isfile(mapout): - self.Logfile.warning('%s: removing map -> %s' %(xtal,mapout)) - os.system('/bin/rm '+mapout) -# else: - - if mapin.endswith('.map') or mapin.endswith('.ccp4'): - cmd = ( - 'mapmask mapin %s mapout %s xyzin %s << eof\n' %(mapin.replace('.ccp4','.P1.ccp4'),mapout,pdbCentre) + - ' border 12\n' - ' end\n' - 'eof' - ) - -# cmd = ( -# 'cmapcut -mapin %s -pdbin %s -mapout %s' %(mtzin,pdbCentre,mapout) -# ) - -# cmd = ( -# "phenix.cut_out_density %s %s map_coeff_labels='%s,%s' cutout_model_radius=6 cutout_map_file_name=%s cutout_as_map=True" %(pdbCentre,mtzin,F,PHI,mapout) -# ) - self.Logfile.insert(xtal+': running command:\n'+cmd) - os.system(cmd) - if os.path.isfile(mapout): - self.Logfile.insert(xtal+': reduced event map successfully created') - self.Logfile.insert('%s: copying %s to %s/files' % (xtal, mapout, self.htmlDir)) - os.system('/bin/cp %s %s/files' % (mapout, self.htmlDir)) - else: - self.Logfile.error(xtal+': creation of event map failed') - - - -# def cut_eventMAP(self,xtal,ligID,eventMAP): -# os.chdir(os.path.join(self.projectDir, xtal)) -# self.Logfile.insert('%s: cutting event map around ligand %s' %(xtal,ligID)) -# ligMAP = xtal + '_' + ligID + '.ccp4' -# cmd = ( -# 'mapmask mapin %s mapout %s xyzin %s << eof\n' %(eventMAP,ligMAP,ligID+'.pdb') + -# ' border 10\n' -# ' end\n' -# 'eof' -# ) -# os.system(cmd) -# self.copy_eventMap(xtal, ligID, eventMAP) - -# def copy_eventMap(self,xtal,ligID,eventMAP): -# os.chdir(os.path.join(self.htmlDir,'files')) -# self.Logfile.insert('%s: copying event map for %s' %(xtal,ligID)) -# os.system('/bin/mv %s/%s_%s.ccp4 .' %(os.path.join(self.projectDir,xtal),xtal,ligID)) - - def get_lig_cc(self, xtal, mtz, lig): - ligID = lig.replace('.pdb','') - ccLog = mtz.replace('.mtz', '_CC'+ligID+'.log') - self.Logfile.insert('%s: calculating CC for %s in %s' %(xtal,lig,mtz)) -# if os.path.isfile(mtz.replace('.mtz', '_CC'+ligID+'.log')): - if os.path.isfile(ccLog) and os.path.getsize(ccLog) != 0: - self.Logfile.warning('logfile of CC analysis exists; skipping...') - return -# cmd = ( 'module load phenix\n' -# 'phenix.get_cc_mtz_pdb %s %s > %s' % (mtz, lig, mtz.replace('.mtz', '_CC'+ligID+'.log')) ) - os.system('/bin/rm %s' %mtz.replace('.mtz', '_CC'+ligID+'.log') ) - cmd = ( 'phenix.get_cc_mtz_pdb %s %s > %s' % (mtz, lig, mtz.replace('.mtz', '_CC'+ligID+'.log')) ) - os.system(cmd) - - def check_lig_cc(self,log): - cc = 'n/a' - if os.path.isfile(log): - for line in open(log): - if line.startswith('local'): - cc = line.split()[len(line.split()) - 1] - else: - self.Logfile.error('logfile does not exist: %s' %log) - return cc - - def write_html_file(self,html): - os.chdir(self.htmlDir) - self.Logfile.insert('writing index.html') - html += XChemMain.html_footer() - if os.path.isfile('index.html'): - os.system('/bin/rm -f index.html') - f = open('index.html','w') - f.write(html) - f.close() - diff --git a/web/process_sqlite.py b/web/process_sqlite.py deleted file mode 100755 index b81a854d..00000000 --- a/web/process_sqlite.py +++ /dev/null @@ -1,361 +0,0 @@ -# last edited: 05/07/2017, 15:00 - -#!/usr/local/anaconda/sgc_default/envs/sgc_default/bin/python - -# Author: Brian Marsden -# -# handover date: 16/12/2016 - -import shutil -import os -import sys -import getopt -import sqlite3 -import csv -import zipfile -import glob - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'),'lib')) - -from rdkit import Chem -from rdkit.Chem import Draw - -targetID = '' -panddadir = '' - -def writeTableRow (row,htmlfile): - "Write a row of data to the HTML file" - htmlfile.write("") - htmlfile.write(""+row['ModelName']+"\n") - htmlfile.write(""+row['CompoundSMILES']+"\n") - htmlfile.write("\n") - htmlfile.write(""+row['PANDDA_site_name']+"\n") - htmlfile.write(""+row['LigandConfidence']+"\n") - htmlfile.write(""+row['ModelStatus']+"\n") - htmlfile.write("\n") - htmlfile.write("
\n") -# htmlfile.write("
\n") - htmlfile.write(""+row['PANDDA_site_comment']+"\n") -# htmlfile.write("TBD\n") -# htmlfile.write("http://www.rcsb.org/pdb/explore/explore.do?structureId=%s\n" %row['Deposition_PDB_ID']) - htmlfile.write('{1!s}\n'.format(row['Deposition_PDB_ID'], row['Deposition_PDB_ID'])) - htmlfile.write(""+row['DataProcessingResolutionHigh']+"\n") - htmlfile.write(""+row['DataProcessingSpaceGroup']+"\n") - htmlfile.write(""+row['DataProcessingUnitCell']+"\n") - htmlfile.write("Save\n") - htmlfile.write("Save\n") - htmlfile.write("Save\n") - htmlfile.write("\n") - return - -def writeICBPage (row,panddadir): - "Write HTML file for ICB visualisation" - icbhtmlfile=open(panddadir+"/icbs/"+row['ModelName']+".html", "w") - icbhtmlfile.write("\n") - icbhtmlfile.write("\n") - icbhtmlfile.write('\n') - icbhtmlfile.write('\n') - icbhtmlfile.write('\n') - icbhtmlfile.write(''+row['ModelName']+'\n') - icbhtmlfile.write("\n") - icbhtmlfile.write("\n") - icbhtmlfile.write("

"+row['CrystalName']+" "+row['CompoundCode']+" event

\n") - icbhtmlfile.write('

Please wait whilst the interactive viewer is loaded!

\n') - icbhtmlfile.write('
\n') - icbhtmlfile.write('\n') -# icbhtmlfile.write('\n') - icbhtmlfile.write('
\n') - icbhtmlfile.write('
\n') - icbhtmlfile.write("\n") - icbhtmlfile.write("\n") - icbhtmlfile.write("\n") - icbhtmlfile.write("\n") - icbhtmlfile.write("
Protein: "+row['CrystalName']+"
Compound ID: "+row['CompoundCode']+"
Compound SMILES: "+row['CompoundSMILES']+"
\n") - icbhtmlfile.write("
\n") - icbhtmlfile.write('\n') - icbhtmlfile.write("\n") - icbhtmlfile.write("\n") - icbhtmlfile.close() - return - -def main (argv): - sqlitefile = '' - # Process command line options - try: - opts, args = getopt.getopt(argv,'t:s:d:',['targetID=','sqlitefile=','panddadir=']) - except getopt.GetoptError as err: - print err - print 'process.py -t -s -d ' - sys.exit(2) - if len(opts)<3: - print 'Missing arguments:' - print 'process.py -t -s -d ' - sys.exit(2) - for opt, arg in opts: - if opt == '-h': - print 'process.py -t -s ' - sys.exit() - elif opt in ("-t", "--targetID"): - targetID = arg - elif opt in ("-s", "--sqlitefile"): - sqlitefile = arg - elif opt in ("-d", "--panddadir"): - panddadir = arg - - # Create directory structure - if not os.path.exists(panddadir+"/compoundImages"): - os.makedirs(panddadir+"/compoundImages") - if not os.path.exists(panddadir+"/icbs"): - os.makedirs(panddadir+"/icbs") - if not os.path.exists(panddadir+"/pdbs"): - os.makedirs(panddadir+"/pdbs") - if not os.path.exists(panddadir+"/maps"): - os.makedirs(panddadir+"/maps") - if not os.path.exists(panddadir+"/residueplots"): - os.makedirs(panddadir+"/residueplots") - if not os.path.exists(panddadir+"/mapImages"): - os.makedirs(panddadir+"/mapImages") - - # Create HTML file and write header - htmlfile = open(panddadir+"/index.html", "w") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write('\n') - htmlfile.write('\n') - htmlfile.write('\n') - htmlfile.write(''+targetID+' Fragment Hits\n') - htmlfile.write('\n') - htmlfile.write('\n') - htmlfile.write('\n') - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("

Ligand-bound models for "+targetID+"

") - htmlfile.write("""

Interpreting 'Ligand confidence'

-

4 - High Confidence: The expected ligand was easily interpretable from clear density, and subsequent refinement was well-behaved. This ligand can be trusted. -
3 - Clear density, unexpected ligand: Density very clearly showed a well-defined ligand, but that ligand was unexpected in that crystal/dataset. The observed ligand was modelled anyway, because its presence could be explained in some way. -
2 - Correct ligand, weak density: Though density was weak, it was possible to model the expected ligand, possibly including other circumstantial evidence (e.g. similar ligand in another model). -
1 - Low Confidence: The ligand model is to be treated with scepticism, because the evidence (density, identity, pose) were not convincing. -

Interpreting 'Model status':

-

6 - Deposited: The model has been deposited in the PDB. -
5 - Deposition ready: The model is fully error-free, in every residue, and is ready for deposition. -
4 - CompChem ready: The model is complete and correct in the region of the bound ligand. There may be remaining small errors elsewhere in the structure, but they are far away and unlikely to be relevant to any computational analysis or compound design. -

Interpreting 'Ligand validation' spider plots:

Each axis represents one of the values described below; small is better, and large values on any axis implies that further investigation is warranted. -

Quality (RSCC) reflects the fit of the atoms to the experimental density, and should typically be greater than 0.7. -
Accuracy (RSZD) measures the amount of difference density that is found around these atoms, and should be below 3. -
B-factor ratio measures the consistency of the model with surrounding protein, and is calculated from the B factors of respectively the changed atoms and all side-chain atoms within 4Å. Large values (>3) reflect poor evidence for the model, and intermediate values (1.5+) indicate errors in refinement or modelling; for weakly-binding ligands, systematically large ratios may be justifiable. -
RMSD compares the positions of all atoms built into event density, with their positions after final refinement, and should be below 1Å. -
Precision (RSZO/OCC) measures how clear the density is after refinement. (This is not a quality indicator, but is related to strength of binding but not in a straightforward way.) -

\n""") - htmlfile.write("

Download data

\n") - htmlfile.write("") - htmlfile.write('\n') - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.write("\n") - - # Now walk through the input data - with open('foricm.csv', 'wb') as f: - with sqlite3.connect(sqlitefile) as c: - c.row_factory=sqlite3.Row - cur=c.cursor() - -# sql = ( "select p.ID,p.CrystalName,p.PANDDA_site_event_index,p.CrystalName || '_event'|| p.PANDDA_site_event_index " -# " as ModelName,m.CompoundCode,m.CompoundSMILES,p.PANDDA_site_name,p.PANDDA_site_confidence " -# " as LigandConfidence,p.RefinementOutcome " -# " as ModelStatus,p.PANDDA_site_comment,p.PANDDA_site_x,p.PANDDA_site_y,p.PANDDA_site_z, " -# " p.PANDDA_site_spider_plot,m.DataProcessingResolutionHigh,m.DataProcessingSpaceGroup," -# " m.DataProcessingUnitCell,m.RefinementPDB_latest,m.RefinementMTZ_latest,p.PANDDA_site_event_map " -# " from panddaTable as p, mainTable as m " -# " where p.CrystalName=m.CrystalName and p.PANDDA_site_ligand_placed='True' and " -# " (LigandConfidence like '1%' or LigandConfidence like '2%' or LigandConfidence like '3%' or LigandConfidence like '4%') " -# " order by p.CrystalName,ModelStatus desc,PANDDA_site_event_index" -# ) - - # query below is without the LigandConfidence being constrained; this is because some older DBs don't have a starting digit - # here we constrain RefinementOutcome of site -# cur.execute("select p.ID,p.CrystalName,p.PANDDA_site_event_index,p.CrystalName || '_event'|| p.PANDDA_site_event_index as ModelName,m.CompoundCode,m.CompoundSMILES,m.Deposition_PDB_ID,p.PANDDA_site_name,p.PANDDA_site_confidence as LigandConfidence,p.RefinementOutcome as ModelStatus,p.PANDDA_site_comment,p.PANDDA_site_x,p.PANDDA_site_y,p.PANDDA_site_z, p.PANDDA_site_spider_plot,m.DataProcessingResolutionHigh,m.DataProcessingSpaceGroup,m.DataProcessingUnitCell,m.RefinementBoundConformation,m.RefinementMTZ_latest,p.PANDDA_site_event_map from panddaTable as p, mainTable as m where p.CrystalName=m.CrystalName and p.PANDDA_site_ligand_placed='True' and (p.RefinementOutcome like '4%' or p.RefinementOutcome like '5%' or p.RefinementOutcome like '6%') order by p.CrystalName,ModelStatus desc,PANDDA_site_event_index") - - - sql = ( - "select p.ID,p.CrystalName,p.PANDDA_site_event_index,p.CrystalName || '_event'|| p.PANDDA_site_event_index " - " as ModelName,m.CompoundCode,m.CompoundSMILES,m.Deposition_PDB_ID,p.PANDDA_site_name," - " p.PANDDA_site_confidence as LigandConfidence," - " p.RefinementOutcome as ModelStatus," - " p.PANDDA_site_comment,p.PANDDA_site_x,p.PANDDA_site_y,p.PANDDA_site_z, p.PANDDA_site_spider_plot," - " m.DataProcessingResolutionHigh,m.DataProcessingSpaceGroup,m.DataProcessingUnitCell," - " m.RefinementBoundConformation,m.RefinementMTZ_latest," - " p.PANDDA_site_event_map from panddaTable as p, " - " mainTable as m where p.CrystalName=m.CrystalName and p.PANDDA_site_ligand_placed='True' " - " and (p.RefinementOutcome like '4%' or p.RefinementOutcome like '5%' or p.RefinementOutcome like '6%') " - " and (LigandConfidence like '1%' or LigandConfidence like '2%' or LigandConfidence like '3%' or LigandConfidence like '4%')" - " order by p.CrystalName,ModelStatus desc,PANDDA_site_event_index" - ) - - sql = ( - "select p.ID,p.CrystalName,p.PANDDA_site_event_index,p.CrystalName || '_event'|| p.PANDDA_site_event_index " - " as ModelName,m.CompoundCode,m.CompoundSMILES,m.Deposition_PDB_ID,p.PANDDA_site_name," - " p.PANDDA_site_confidence as LigandConfidence," - " p.RefinementOutcome as ModelStatus," - " p.PANDDA_site_comment,p.PANDDA_site_x,p.PANDDA_site_y,p.PANDDA_site_z, p.PANDDA_site_spider_plot," - " m.DataProcessingResolutionHigh,m.DataProcessingSpaceGroup,m.DataProcessingUnitCell," - " m.RefinementBoundConformation,m.RefinementMTZ_latest," - " p.PANDDA_site_event_map from panddaTable as p, " - " mainTable as m where p.CrystalName=m.CrystalName and p.PANDDA_site_ligand_placed='True' " - " and (m.RefinementOutcome like '4%' or m.RefinementOutcome like '5%' or m.RefinementOutcome like '6%') " - " and (LigandConfidence like '1%' or LigandConfidence like '2%' or LigandConfidence like '3%' or LigandConfidence like '4%')" - " order by p.CrystalName,ModelStatus desc,PANDDA_site_event_index" - ) - - cur.execute(sql) - - rows=cur.fetchall() - if not rows: - print '==> WARNING: none of your samples seems to be at least CompChem ready (4)' - return None - writer = csv.DictWriter(f, fieldnames=rows[1].keys()) - writer.writeheader() - for row in rows: - # Make compound structure - print row['ModelName'],row['PANDDA_site_spider_plot'] - compound=Chem.MolFromSmiles(row['CompoundSMILES'].encode("ascii")) - Draw.MolToFile(compound,panddadir+'/compoundImages/'+row['CompoundCode']+'.png',(150,150)) - # Write out table information for event - eventID=row['ModelName']+"_"+row['CompoundCode'] - actID=(row['ModelName']+row['CompoundCode']).replace(targetID+'-','') - writeTableRow(row,htmlfile) - writeICBPage(row,panddadir) - try: - shutil.copy(row['RefinementBoundConformation'],panddadir+"/pdbs/"+row['ModelName']+".pdb") - shutil.copy(row['RefinementMTZ_latest'],panddadir+"/maps/"+row['ModelName']+".mtz") - shutil.copy(row['PANDDA_site_event_map'],panddadir+"/maps/"+row['ModelName']+".ccp4") - if row['PANDDA_site_spider_plot'] is not None: - shutil.copy(row['PANDDA_site_spider_plot'],panddadir+"/residueplots/"+row['ModelName']+".png") - except (IOError,TypeError): - print '*** WARNING: cannot find PDB and/or MTZ of '+row['ModelName']+' ***' - print 'PDB bound :', row['RefinementBoundConformation'] - print 'MTZ :', row['RefinementMTZ_latest'] - print 'event map :', row['PANDDA_site_event_map'] - print 'spider plot:', row['PANDDA_site_spider_plot'] - pass -# shutil.copy(row['RefinementPDB_latest'],panddadir+"/pdbs/"+row['ModelName']+".pdb") -# if row['PANDDA_site_spider_plot'] is not None: -# shutil.copy(row['PANDDA_site_spider_plot'],panddadir+"/residueplots/"+row['ModelName']+".png") - # Write row to CSV for ICM - writer.writerow(dict(row)) - - # Conclude HTML - htmlfile.write("\n") - htmlfile.write("
Model NameCompound SMILESCompound StructureSite NameLigand ConfidenceModel StatusLigand ValidationEvent Map 3DCommentPDB IdentifierResolSpacegroupCellPDBMTZEvent Map
Model NameCompound SMILESCompound StructureSite NameLigand ConfidenceModel StatusLigand ValidationEvent Map 3DCommentPDB IdentifierResolSpacegroupCellPDBMTZEvent Map
\n") - htmlfile.write("\n") - htmlfile.write("\n") - htmlfile.close() - - # Copy JS & CSS files - if not os.path.exists(panddadir+"/js"): - os.makedirs(panddadir+"/js") - if not os.path.exists(panddadir+"/css"): - os.makedirs(panddadir+"/css") - shutil.copy(os.path.join(os.getenv('XChemExplorer_DIR'),"web/jscss/css/jquery.dataTables.min.css"),panddadir+"/css/jquery.dataTables.min.css") - shutil.copy(os.path.join(os.getenv('XChemExplorer_DIR'),"web/jscss/js/jquery-1.12.3.min.js"),panddadir+"/js/jquery-1.12.3.min.js") - shutil.copy(os.path.join(os.getenv('XChemExplorer_DIR'),"web/jscss/js/jquery.dataTables.min.js"),panddadir+"/js/jquery.dataTables.min.js") - - # Create zip files - print "Creating zipfile of PDBs..." - os.chdir(panddadir+"/pdbs") - zf=zipfile.ZipFile("allPDBs.zip","w") - for pdb in glob.glob("*.pdb"): - zf.write(pdb) - zf.close() - - print "Creatig zipfile of event maps..." - os.chdir("../maps") - zf=zipfile.ZipFile("allEventMaps.zip","w") - for pdb in glob.glob("*.mtz"): - zf.write(pdb) - zf.close() - - # change folder permissions - os.system('chmod -R 775 {0!s}'.format(panddadir)) - - return - -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/xce/XChemExplorer.py b/xce/XChemExplorer.py new file mode 100755 index 00000000..3974adf5 --- /dev/null +++ b/xce/XChemExplorer.py @@ -0,0 +1,5859 @@ +import getpass +import glob +import math +import os +import pickle +import sys +from datetime import datetime + +from PyQt4 import QtCore, QtGui + +from xce.gui_scripts import layout, layout_functions, stylesheet +from xce.lib import ( + XChemDB, + XChemDeposit, + XChemLog, + XChemMain, + XChemPANDDA, + XChemPlots, + XChemThread, + XChemToolTips, +) +from xce.lib.XChemUtils import parse +from xce.lib.cluster.slurm import get_token, fetch_password_qt +from xce.web import XChemWeb + + +class XChemExplorer(QtGui.QApplication): + def __init__(self, args): + # init a QApplication object to hold XCE + QtGui.QApplication.__init__(self, args) + + # start GUI + self.start_GUI() + + # set stylesheet - how the gui looks + stylesheet.set_stylesheet(self) + + self.exec_() + + def start_GUI(self): + # check http://doc.qt.io/qt-4.8/stylesheet-customizing.html#the-box-model + # This needs moving somewhere more appropriate... + self.headlineLabelfont = QtGui.QFont("Arial", 20, QtGui.QFont.Bold) + + layout.setup().settings(self) + layout.setup().preferences(self) + layout.setup().tables(self) + + # GUI setup + self.window = QtGui.QWidget() + self.window.setWindowTitle("XChemExplorer") + self.screen = QtGui.QDesktopWidget().screenGeometry() + + layout.LayoutObjects().workflow(self) + layout.LayoutObjects().main_layout(self) + layout_functions.add_widgets_layouts(self) + + self.checkLabXChemDir() + + if os.path.isfile(os.path.join(self.database_directory, self.data_source_file)): + self.backup_soakDB() + + def backup_soakDB(self): + XChemMain.backup_soakDB( + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ) + + def checkLabXChemDir(self): + dirCheck = QtGui.QMessageBox() + dirCheckLayout = dirCheck.layout() + vbox = QtGui.QVBoxLayout() + try: + warning = ( + "Are you sure you want to launch XCE here:\n\n" + + self.labxchem_directory_current + + "\n\n" + "If this is not where you should be running XCE, please close!\n" + ) + except AttributeError: + return + vbox.addWidget(QtGui.QLabel(warning)) + dirCheckLayout.addLayout(vbox, 0, 0) + dirCheck.exec_() + + # function to update datasource + + def datasource_menu_reload_samples(self): + self.update_log.insert( + "reading samples from data source: " + + os.path.join(self.database_directory, self.data_source_file) + ) + self.update_status_bar( + "reading samples from data source: " + + os.path.join(self.database_directory, self.data_source_file) + ) + self.update_header_and_data_from_datasource() + self.update_all_tables() + self.overview_datasource_table.resizeColumnsToContents() + + # function to create new datasource + def create_new_data_source(self): + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, "Save file", self.database_directory + ) + ) + # make sure that the file always has .sqlite extension + if file_name.rfind(".") != -1: + file_name = file_name[: file_name.rfind(".")] + ".sqlite" + else: + file_name = file_name + ".sqlite" + self.db = XChemDB.data_source(file_name) + print("==> XCE: creating new data source") + self.db.create_empty_data_source_file() + self.db.create_missing_columns() + self.database_directory = file_name[: file_name.rfind("/")] + self.data_source_file = file_name[file_name.rfind("/") + 1 :] + self.data_source_file_label.setText( + os.path.join(self.database_directory, self.data_source_file) + ) + self.settings["database_directory"] = self.database_directory + self.settings["data_source"] = self.data_source_file + self.data_source_set = True + self.datasource_menu_reload_samples() + + #################################################################################### + # # + # DATASETS TAB # + # # + #################################################################################### + + def continously_check_for_new_data_collection(self, state): + self.timer_to_check_for_new_data_collection.timeout.connect( + lambda: self.check_for_new_autoprocessing_or_rescore(False) + ) + if state == QtCore.Qt.Checked: + print("==> XCE: checking automatically every 120s for new data collection") + self.timer_to_check_for_new_data_collection.start(120000) + else: + print("==> XCE: stopped checking for new data collections") + self.timer_to_check_for_new_data_collection.stop() + + def target_selection_combobox_activated(self, text): + self.target = str(text) + + def check_for_new_autoprocessing_or_rescore(self, rescore_only): + self.update_log.insert("checking for new data collection") + start_thread = False + if rescore_only: + # first pop up a warning message as this will overwrite all user selections + msgBox = QtGui.QMessageBox() + msgBox.setText( + "*** WARNING ***\n" + "This will overwrite all your manual selections!\n" + "Do you want to continue?" + ) + msgBox.addButton(QtGui.QPushButton("Yes"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("No"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + if reply == 0: + start_thread = True + else: + start_thread = False + else: + start_thread = True + + if start_thread: + if self.target == "=== SELECT TARGET ===": + msgBox = QtGui.QMessageBox() + warning = ( + "*** WARNING ***\n" + "Please select a target or\n" + 'select "=== project directory ==="' + " if you want to read reprocessed results\n" + "In case target list is empty," + " make sure that you have selected the actual\n" + "data collection visit (e.g. /dls/i04-1/data/2018/lb18145-70)" + ) + msgBox.setText(warning) + start_thread = False + + if start_thread: + self.work_thread = XChemThread.read_autoprocessing_results_from_disc( + self.visit_list, + self.target, + self.reference_file_list, + self.database_directory, + self.data_collection_dict, + self.preferences, + self.datasets_summary_file, + self.initial_model_directory, + rescore_only, + self.acceptable_low_resolution_limit_for_data, + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("create_widgets_for_autoprocessing_results_only"), + self.create_widgets_for_autoprocessing_results_only, + ) + self.work_thread.start() + + #################################################################################### + # + # + # + # => for new module from hell + # > start + + def update_gdaLog_parsing_instructions_and_score(self, gdaLogInstructions): + self.gdaLogInstructions = gdaLogInstructions + self.select_best_autoprocessing_result() + + def read_pinIDs_from_gda_logs(self): + self.update_log.insert("reading pinIDs from gda logfiles...") + visit, beamline = XChemMain.getVisitAndBeamline(self.beamline_directory) + self.work_thread = XChemThread.read_pinIDs_from_gda_logs( + beamline, + visit, + os.path.join(self.database_directory, self.data_source_file), + self.gdaLogInstructions, + self.xce_logfile, + ) + + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_gdaLog_parsing_instructions_and_score"), + self.update_gdaLog_parsing_instructions_and_score, + ) + self.work_thread.start() + + def check_for_new_autoprocessing_results(self): + self.update_log.insert("checking for new data collection") + if self.target == "=== SELECT TARGET ===": + self.update_log.error( + "NO TARGET SELECTED, PLEASE SELECT A TARGET AND TRY AGAIN!" + ) + start_thread = False + elif self.target == "=== project directory ===": + processedDir = self.initial_model_directory + start_thread = True + else: + processedDir = os.path.join( + self.beamline_directory, "processed", self.target + ) + start_thread = True + + if start_thread: + self.work_thread = ( + XChemThread.read_write_autoprocessing_results_from_to_disc( + processedDir, + os.path.join(self.database_directory, self.data_source_file), + self.initial_model_directory, + self.xce_logfile, + self.target, + self.read_agamemnon.isChecked(), + ) + ) + + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("read_pinIDs_from_gda_logs"), + self.read_pinIDs_from_gda_logs, + ) + self.work_thread.start() + + def select_best_autoprocessing_result(self): + if self.rescore: + # first pop up a warning message as this will overwrite all user selections + msgBox = QtGui.QMessageBox() + msgBox.setText( + "*** WARNING ***\n" + "This will overwrite all your manual selections!\n" + "Do you want to continue?" + ) + msgBox.addButton(QtGui.QPushButton("Yes"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("No"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + if reply != 0: + start_thread = False + else: + start_thread = True + else: + start_thread = True + + if start_thread: + self.update_log.insert("selecting best autoprocessing result") + self.update_log.insert( + "samples where user made manual changes will be ignored!" + ) + + if self.target == "=== project directory ===": + processedDir = self.initial_model_directory + else: + processedDir = os.path.join( + self.beamline_directory, "processed", self.target + ) + + visit, beamline = XChemMain.getVisitAndBeamline(processedDir) + + if self.read_agamemnon.isChecked(): + visit = [] + for v in glob.glob( + os.path.join( + self.beamline_directory[ + : self.beamline_directory.rfind("-") + 1 + ] + + "*" + ) + ): + visit.append(v[v.rfind("/") + 1 :]) + + self.work_thread = XChemThread.choose_autoprocessing_outcome( + os.path.join(self.database_directory, self.data_source_file), + visit, + self.reference_file_list, + self.preferences, + self.initial_model_directory, + self.rescore, + self.xce_logfile, + self.read_agamemnon.isChecked(), + ) + + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("populate_datasets_summary_table_NEW"), + self.populate_datasets_summary_table_NEW, + ) + self.work_thread.start() + + # < end + #################################################################################### + + #################################################################################### + # # + # MAPS TAB # + # # + #################################################################################### + + def set_new_reference_if_applicable(self): + print("hallo") + reference_root = str(self.reference_file_selection_combobox.currentText()) + pg_ref = "" + ucVol_ref = 0.0 + for reference in self.reference_file_list: + print((reference[0], reference_root)) + if reference[0] == reference_root: + pg_ref = reference[5] + ucVol_ref = reference[4] + break + if ucVol_ref == 0.0: + self.update_log.insert( + "cannot set reference file" + " since unit cell volume of reference pdb is 0!" + ) + return + + for xtal in self.initial_model_dimple_dict: + reference_file_selection_combobox = self.initial_model_dimple_dict[xtal][1] + self.populate_reference_combobox(reference_file_selection_combobox) + db_dict = self.xtal_db_dict[xtal] + pg_xtal = db_dict["DataProcessingPointGroup"] + ucVol_xtal = db_dict["DataProcessingUnitCellVolume"] + + try: + difference = math.fabs(1 - (float(ucVol_xtal) / float(ucVol_ref))) * 100 + except ValueError: + self.update_log.insert( + xtal + " -> cannot calculate unit cell volume difference" + ) + continue + + if ( + pg_xtal == pg_ref + and difference < self.allowed_unitcell_difference_percent + ): + print((xtal, pg_xtal, ucVol_xtal)) + index = reference_file_selection_combobox.findText( + reference_root, QtCore.Qt.MatchFixedString + ) + reference_file_selection_combobox.setCurrentIndex(index) + self.update_log.insert( + xtal + + " -> setting " + + reference_root + + " as input PDB file for DIMPLE" + ) + + def refresh_reference_file_list(self): + self.reference_file_list = self.get_reference_file_list(" ") + self.populate_reference_combobox(self.reference_file_selection_combobox) + + def on_context_menu_initial_model(self, point): + # show context menu + self.popMenu_for_maps_table.exec_(self.sender().mapToGlobal(point)) + + #################################################################################### + # # + # PANDDA TAB # + # # + #################################################################################### + def select_pandda_input_template(self): + mtzin = "" + filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter( + self.window, + "Select Example PDB or MTZ File", + self.initial_model_directory, + "*.pdb;;*.mtz", + ) + filepath = str(tuple(filepath_temp)[0]) + pdbin = filepath.split("/")[-1] + if filepath.endswith(".pdb"): + pdbin = filepath.split("/")[-1] + mtzin_temp = pdbin.replace(".pdb", ".mtz") + if os.path.isfile(filepath.replace(pdbin, mtzin_temp)): + mtzin = mtzin_temp + else: + mtzin = "" + if filepath.endswith(".mtz"): + mtzin = filepath.split("/")[-1] + pdbin_temp = pdbin.replace(".mtz", ".pdb") + if os.path.isfile(filepath.replace(mtzin, pdbin_temp)): + pdbin = pdbin_temp + else: + pdbin = "" + + try: + self.pandda_input_data_dir_entry.setText( + "/" + + os.path.join(*filepath.split("/")[0 : len(filepath.split("/")) - 2]) + ) + except TypeError: + self.update_log.error("directory selection invalid") + self.pandda_pdb_style_entry.setText(pdbin) + self.pandda_mtz_style_entry.setText(mtzin) + + def change_pandda_spg_label(self): + combo_text = str(self.pandda_reference_file_selection_combobox.currentText()) + for file in self.reference_file_list: + if file[0] == combo_text: + self.pandda_reference_file_spg_label.setText(file[1]) + break + + def on_context_menu_pandda(self, point): + # show context menu + self.popMenu_for_pandda_table.exec_(self.sender().mapToGlobal(point)) + + #################################################################################### + # # + # DEPO TAB # + # # + #################################################################################### + def export_to_html(self): + XChemWeb.export_to_html( + self.html_export_directory, + self.initial_model_directory, + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ).prepare("0") + + def export_to_html_CompChem(self): + XChemWeb.export_to_html( + self.html_export_directory, + self.initial_model_directory, + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ).prepare("4") + + def export_to_html_deposition_ready(self): + XChemWeb.export_to_html( + self.html_export_directory, + self.initial_model_directory, + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ).prepare("5") + + def add_ground_state_db(self): + pdb, mtz = self.auto_select_ground_state_reference_PDB() + if pdb is not None: + db_dict = { + "DimplePANDDApath": self.panddas_directory, + "PDB_file": pdb, + "MTZ_file": mtz, + } + self.db.create_or_remove_missing_records_in_depositTable( + self.xce_logfile, "ground_state", "ground_state", db_dict + ) + else: + self.update_log.error( + "could not find a suitable reference file; see messages above!" + ) + + def auto_select_ground_state_reference_PDB(self): + pdb = None + mtz = None + xtalList = [] + for dirs in glob.glob( + os.path.join(self.panddas_directory, "processed_datasets", "*") + ): + xtal = dirs[dirs.rfind("/") + 1 :] + if os.path.isfile(os.path.join(dirs, xtal + "-pandda-input.pdb")): + pdbHeader = parse().PDBheader( + os.path.join(dirs, xtal + "-pandda-input.pdb") + ) + try: + xtalList.append( + [ + xtal, + float(pdbHeader["Rfree"]), + float(pdbHeader["ResolutionHigh"]), + ] + ) + except ValueError: + self.update_log.error( + "%s: cannot read Rfree or Resolution from PDB header;" + " skipping..." + ) + pass + self.update_log.insert( + "found %s PDB files in %s" + % ( + str(len(xtalList)), + os.path.join(self.panddas_directory, "processed_datasets"), + ) + ) + if len(xtalList) >= 10: + self.update_log.insert( + "sorting PDBs by Rfree and selecting the 10 with lowest value" + ) + rfree = sorted(xtalList, key=lambda x: x[1])[:10] + self.update_log.insert("top 10 PDB files with lowest Rfree:") + for item in rfree: + self.update_log.insert( + "%s: Rfree = %s | Resolution = %s" + % (item[0], str(round(item[1], 3)), str(round(item[2], 2))) + ) + self.update_log.insert("selecting PDB with highest resolution") + reso = sorted(rfree, key=lambda x: x[2])[:1] + self.update_log.insert( + "selected the following PDB file: %s: Rfree = %s | Resolution = %s" + % (reso[0][0], str(round(reso[0][1], 3)), str(round(reso[0][2], 2))) + ) + pdb = os.path.join( + self.panddas_directory, + "processed_datasets", + reso[0][0], + reso[0][0] + "-pandda-input.pdb", + ) + mtz = os.path.join( + self.panddas_directory, + "processed_datasets", + reso[0][0], + reso[0][0] + "-pandda-input.mtz", + ) + else: + self.update_log.error( + "found less than 10 valid PDB files in %s" + % os.path.join(self.panddas_directory, "processed_datasets") + ) + return pdb, mtz + + def prepare_ground_state_mmcif(self): + self.update_log.insert("preparing mmcif file for apo structure deposition") + self.prepare_models_for_deposition_ligand_bound("ground_state") + + #################################################################################### + # # + # SETTINGS TAB # + # # + #################################################################################### + def settings_button_clicked(self): + if self.sender().text() == "Select Project Directory": + self.initial_model_directory = str( + QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory") + ) + self.initial_model_directory_label.setText(self.initial_model_directory) + self.pandda_input_data_dir_entry.setText(self.initial_model_directory) + self.settings["initial_model_directory"] = self.initial_model_directory + if self.sender().text() == "Select Reference Structure Directory": + reference_directory_temp = str( + QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory") + ) + if reference_directory_temp != self.reference_directory: + self.reference_directory = reference_directory_temp + self.update_reference_files(" ") + self.reference_directory_label.setText(self.reference_directory) + self.settings["reference_directory"] = self.reference_directory + if self.sender().text() == "Select Data Source File": + filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter( + self.window, "Select File", self.database_directory, "*.sqlite" + ) + filepath = str(tuple(filepath_temp)[0]) + self.data_source_file = filepath.split("/")[-1] + self.database_directory = filepath[: filepath.rfind("/")] + self.settings["database_directory"] = self.database_directory + self.settings["data_source"] = os.path.join( + self.database_directory, self.data_source_file + ) + write_enabled = self.check_write_permissions_of_data_source() + if not write_enabled: + self.data_source_set = False + else: + self.data_source_set = True + self.data_source_file_label.setText( + os.path.join(self.database_directory, self.data_source_file) + ) + self.db = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ) + self.db.create_missing_columns() + self.datasource_menu_reload_samples() + if self.sender().text() == "Select Data Collection Directory": + dir_name = str( + QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory") + ) + if dir_name != self.beamline_directory: + self.beamline_directory = dir_name + self.target_list, self.visit_list = XChemMain.get_target_and_visit_list( + self.beamline_directory, self.read_agamemnon.isChecked() + ) + self.populate_target_selection_combobox(self.target_selection_combobox) + self.beamline_directory_label.setText(self.beamline_directory) + self.settings["beamline_directory"] = self.beamline_directory + + if self.sender().text() == "Select Existing\nCollection Summary File": + if self.datasets_summary_file != "": + filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter( + self.window, + "Select File", + self.datasets_summary_file[: self.datasets_summary_file.rfind("/")], + "*.pkl", + ) + else: + filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter( + self.window, "Select File", os.getcwd(), "*.pkl" + ) + filepath = str(tuple(filepath_temp)[0]) + self.datasets_summary_file = filepath + self.datasets_summary_file_label.setText(self.datasets_summary_file) + self.settings["datasets_summary"] = self.datasets_summary_file + + if self.sender().text() == "Assign New\nCollection Summary File": + if self.datasets_summary_file != "": + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, + "New file", + self.datasets_summary_file[ + : self.datasets_summary_file.rfind("/") + ], + ) + ) + else: + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, "New file", self.current_directory + ) + ) + # make sure that the file always has .pkl extension + if str(file_name).rfind(".") != -1: + file_name = file_name[: file_name.rfind(".")] + ".pkl" + else: + file_name = file_name + ".pkl" + self.datasets_summary_file = file_name + self.datasets_summary_file_label.setText(self.datasets_summary_file) + self.settings["datasets_summary"] = self.datasets_summary_file + + if self.sender().text() == "Select CCP4_SCR Directory": + self.ccp4_scratch_directory = str( + QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory") + ) + self.ccp4_scratch_directory_label.setText(self.ccp4_scratch_directory) + self.settings["ccp4_scratch"] = self.ccp4_scratch_directory + if self.sender().text() == "Select PanDDA Directory": + self.panddas_directory = str( + QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory") + ) + self.panddas_directory_label.setText(self.panddas_directory) + self.pandda_output_data_dir_entry.setText(self.panddas_directory) + self.ground_state_pandda_directory_label.setText(self.panddas_directory) + print(("PANDDA", self.panddas_directory)) + self.settings["panddas_directory"] = self.panddas_directory + + layout_functions.pandda_html(self) + + if self.sender().text() == "Select HTML Export Directory": + self.html_export_directory = str( + QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory") + ) + self.html_export_directory_label.setText(self.html_export_directory) + self.settings["html_export_directory"] = self.html_export_directory + + if self.sender().text() == "Select Group deposition Directory": + self.group_deposit_directory = str( + QtGui.QFileDialog.getExistingDirectory(self.window, "Select Directory") + ) + self.group_deposition_directory_label.setText(self.group_deposit_directory) + self.settings["group_deposit_directory"] = self.group_deposit_directory + + # ############################## sort stuff below here ############################# + + def select_sample_for_dimple(self): + indexes = self.maps_table.selectionModel().selectedRows() + for index in sorted(indexes): + xtal = str(self.maps_table.item(index.row(), 0).text()) + self.update_log.insert("{0!s} is marked for DIMPLE".format(index.row())) + self.initial_model_dimple_dict[xtal][0].setChecked(True) + + def update_summary_plot(self): + if self.data_source_set: + XChemPlots.summary_plot( + os.path.join(self.database_directory, self.data_source_file), + self.overview_axes, + ).update_overview() + self.overview_canvas.draw() + + def show_preferences(self): + preferences = QtGui.QMessageBox() + preferencesLayout = preferences.layout() + + vbox = QtGui.QVBoxLayout() + settings_hbox_filename_root = QtGui.QHBoxLayout() + filename_root_label = QtGui.QLabel("filename root:") + settings_hbox_filename_root.addWidget(filename_root_label) + filename_root_input = QtGui.QLineEdit() + filename_root_input.setFixedWidth(400) + filename_root_input.setText(str(self.filename_root)) + filename_root_input.textChanged[str].connect(self.change_filename_root) + settings_hbox_filename_root.addWidget(filename_root_input) + vbox.addLayout(settings_hbox_filename_root) + + settings_hbox_adjust_allowed_unit_cell_difference = QtGui.QHBoxLayout() + adjust_allowed_unit_cell_difference_label = QtGui.QLabel( + "Max. Allowed Unit Cell Difference between Reference and Target (%):" + ) + settings_hbox_adjust_allowed_unit_cell_difference.addWidget( + adjust_allowed_unit_cell_difference_label + ) + adjust_allowed_unit_cell_difference = QtGui.QLineEdit() + adjust_allowed_unit_cell_difference.setFixedWidth(200) + adjust_allowed_unit_cell_difference.setText( + str(self.allowed_unitcell_difference_percent) + ) + adjust_allowed_unit_cell_difference.textChanged[str].connect( + self.change_allowed_unitcell_difference_percent + ) + settings_hbox_adjust_allowed_unit_cell_difference.addWidget( + adjust_allowed_unit_cell_difference + ) + vbox.addLayout(settings_hbox_adjust_allowed_unit_cell_difference) + + settings_hbox_acceptable_low_resolution_limit = QtGui.QHBoxLayout() + adjust_acceptable_low_resolution_limit_label = QtGui.QLabel( + "Acceptable low resolution limit for datasets (in Angstrom):" + ) + settings_hbox_acceptable_low_resolution_limit.addWidget( + adjust_acceptable_low_resolution_limit_label + ) + adjust_acceptable_low_resolution_limit = QtGui.QLineEdit() + adjust_acceptable_low_resolution_limit.setFixedWidth(200) + adjust_acceptable_low_resolution_limit.setText( + str(self.acceptable_low_resolution_limit_for_data) + ) + adjust_acceptable_low_resolution_limit.textChanged[str].connect( + self.change_acceptable_low_resolution_limit + ) + settings_hbox_acceptable_low_resolution_limit.addWidget( + adjust_acceptable_low_resolution_limit + ) + vbox.addLayout(settings_hbox_acceptable_low_resolution_limit) + + vbox_data = QtGui.QVBoxLayout() + vbox_data.addWidget( + QtGui.QLabel( + "Select amount of processed data you wish to copy to initial_model" + " directory:" + ) + ) + self.preferences_data_to_copy_combobox = QtGui.QComboBox() + for item in self.preferences_data_to_copy: + self.preferences_data_to_copy_combobox.addItem(item[0]) + self.preferences_data_to_copy_combobox.currentIndexChanged.connect( + self.preferences_data_to_copy_combobox_changed + ) + vbox_data.addWidget(self.preferences_data_to_copy_combobox) + vbox.addLayout(vbox_data) + + vbox_select = QtGui.QVBoxLayout() + vbox_select.addWidget(QtGui.QLabel("Dataset Selection Mechanism:")) + self.preferences_selection_mechanism_combobox = QtGui.QComboBox() + for item in self.preferences_selection_mechanism: + self.preferences_selection_mechanism_combobox.addItem(item) + self.preferences_selection_mechanism_combobox.currentIndexChanged.connect( + self.preferences_selection_mechanism_combobox_changed + ) + index = self.preferences_selection_mechanism_combobox.findText( + self.preferences["dataset_selection_mechanism"], QtCore.Qt.MatchFixedString + ) + self.preferences_selection_mechanism_combobox.setCurrentIndex(index) + vbox_select.addWidget(self.preferences_selection_mechanism_combobox) + vbox.addLayout(vbox_select) + + vbox_restraints = QtGui.QVBoxLayout() + vbox_restraints.addWidget(QtGui.QLabel("Restraints generation program:")) + self.preferences_restraints_generation_combobox = QtGui.QComboBox() + program_list = [] + + if self.external_software["acedrg"]: + program_list.append("acedrg") + if self.external_software["phenix.elbow"]: + program_list.append("phenix.elbow") + if self.external_software["grade"]: + program_list.append("grade") + for item in program_list: + self.preferences_restraints_generation_combobox.addItem(item) + self.preferences_restraints_generation_combobox.currentIndexChanged.connect( + self.preferences_restraints_generation_combobox_changed + ) + index = self.preferences_restraints_generation_combobox.findText( + self.restraints_program, QtCore.Qt.MatchFixedString + ) + self.preferences_restraints_generation_combobox.setCurrentIndex(index) + vbox_restraints.addWidget(self.preferences_restraints_generation_combobox) + vbox.addLayout(vbox_restraints) + + hbox = QtGui.QHBoxLayout() + hbox.addWidget(QtGui.QLabel("XCE logfile:")) + self.xce_logfile_label = QtGui.QLabel(self.xce_logfile) + hbox.addWidget(self.xce_logfile_label) + button = QtGui.QPushButton("Change") + button.clicked.connect(self.set_xce_logfile) + hbox.addWidget(button) + vbox.addLayout(hbox) + + settings_hbox_max_queue_jobs = QtGui.QHBoxLayout() + adjust_max_queue_jobs_label = QtGui.QLabel( + "Max. number of jobs running at once on DLS cluster:" + ) + settings_hbox_max_queue_jobs.addWidget(adjust_max_queue_jobs_label) + adjust_max_queue_jobs = QtGui.QLineEdit() + adjust_max_queue_jobs.setFixedWidth(200) + adjust_max_queue_jobs.setText(str(self.max_queue_jobs)) + adjust_max_queue_jobs.textChanged[str].connect(self.change_max_queue_jobs) + settings_hbox_max_queue_jobs.addWidget(adjust_max_queue_jobs) + vbox.addLayout(settings_hbox_max_queue_jobs) + + settings_hbox_dimple_twin_mode = QtGui.QHBoxLayout() + self.dimple_twin_mode_label_checkbox = QtGui.QCheckBox( + "run DIMPLE in TWIN mode" + ) + if self.preferences["dimple_twin_mode"]: + self.dimple_twin_mode_label_checkbox.setChecked(True) + self.dimple_twin_mode_label_checkbox.toggled.connect( + self.dimple_change_twin_mode + ) + settings_hbox_dimple_twin_mode.addWidget(self.dimple_twin_mode_label_checkbox) + vbox.addLayout(settings_hbox_dimple_twin_mode) + + hbox = QtGui.QHBoxLayout() + hbox.addWidget(QtGui.QLabel("Additional CIF file for non-standard ligand:")) + self.second_cif_file_label = QtGui.QLabel(self.second_cif_file) + hbox.addWidget(self.second_cif_file_label) + button = QtGui.QPushButton("Select") + button.clicked.connect(self.set_second_cif_file) + hbox.addWidget(button) + vbox.addLayout(hbox) + + preferencesLayout.addLayout(vbox, 0, 0) + + preferences.exec_() + + def dimple_change_twin_mode(self): + if self.preferences["dimple_twin_mode"]: + self.update_log.insert( + "changing preferences: turning off DIMPLE in TWIN mode" + ) + self.preferences["dimple_twin_mode"] = False + else: + self.update_log.insert("changing preferences: changing DIMPLE to TWIN mode") + self.preferences["dimple_twin_mode"] = True + + def enter_pdb_codes(self): + pdbID_entry = QtGui.QMessageBox() + pdbID_entryLayout = pdbID_entry.layout() + + vbox = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("Text from PDB email"), 0, 0) + self.pdb_code_entry = QtGui.QTextEdit() + self.pdb_code_entry.setText("") + self.pdb_code_entry.setFixedWidth(500) + grid.addWidget(self.pdb_code_entry, 1, 0, 20, 1) + + frame.setLayout(grid) + vbox.addWidget(frame) + + hbox = QtGui.QHBoxLayout() + button = QtGui.QPushButton("Update Database") + button.clicked.connect(self.update_database_with_pdb_codes) + hbox.addWidget(button) + + vbox.addLayout(hbox) + pdbID_entryLayout.addLayout(vbox, 0, 0) + pdbID_entry.exec_() + + def add_label_information(self): + label_entry = QtGui.QMessageBox() + label_entryLayout = label_entry.layout() + + try: + labelInfo = self.db.get_label_info_from_db() + except AttributeError: + self.update_log.warning("please specify DB file first") + return None + + vbox = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + grid.addWidget(QtGui.QLabel("label"), 0, 0) + grid.addWidget(QtGui.QLabel("description"), 0, 1) + + self.labelList = [] + for i in range(5): + labelEdit = QtGui.QLineEdit() + descriptionEdit = QtGui.QLineEdit() + grid.addWidget(labelEdit, i + 1, 0) + grid.addWidget(descriptionEdit, i + 1, 1) + try: + labelEdit.setText(labelInfo[i][0]) + descriptionEdit.setText(labelInfo[i][1]) + except IndexError: + labelEdit.setText("") + descriptionEdit.setText("") + labelEdit.setFixedWidth(100) + descriptionEdit.setFixedWidth(500) + self.labelList.append([labelEdit, descriptionEdit]) + frame.setLayout(grid) + vbox.addWidget(frame) + + hbox = QtGui.QHBoxLayout() + button = QtGui.QPushButton("Update Database") + button.clicked.connect(self.update_database_with_labelInfo) + hbox.addWidget(button) + + vbox.addLayout(hbox) + label_entryLayout.addLayout(vbox, 0, 0) + label_entry.exec_() + + def prepare_models_for_deposition_ligand_bound(self, structureType): + start_thread = True + self.update_log.insert("preparing mmcif files for PDB group deposition...") + ignore_event_map = False + if structureType == "ground_state": + try: + self.update_log.insert("ground-state deposition") + data_template_dict = self.db.get_deposit_dict_for_sample("ground_state") + pdb = data_template_dict["PDB_file"] + self.update_log.insert("looking for ground-state PDB: " + pdb) + if not os.path.isfile(pdb): + self.update_log.error( + "ground-state PDB does not exist; stopping..." + ) + start_thread = False + mtz = data_template_dict["MTZ_file"] + self.update_log.insert("looking for ground-state MTZ: " + mtz) + if not os.path.isfile(mtz): + self.update_log.error( + "ground-state MTZ does not exist; stopping..." + ) + start_thread = False + ground_state = [pdb, mtz, self.panddas_directory] + except KeyError: + self.update_log.error( + "seems like there is no entry for ground-state in database" + ) + start_thread = False + else: + ground_state = [] + if self.deposition_bounnd_state_preparation_ignore_event_map.isChecked(): + ignore_event_map = True + + if start_thread: + if ground_state != []: + self.update_log.insert("apo PDB: " + ground_state[0]) + self.update_log.insert("apo MTZ: " + ground_state[1]) + self.update_log.insert("pandda directory: " + ground_state[2]) + overwrite_existing_mmcif = True + self.work_thread = XChemDeposit.prepare_mmcif_files_for_deposition( + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + overwrite_existing_mmcif, + self.initial_model_directory, + ground_state, + ignore_event_map, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def prepare_for_group_deposition_upload_ligand_bound(self): + self.work_thread = XChemDeposit.prepare_for_group_deposition_upload( + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + self.group_deposit_directory, + self.initial_model_directory, + "ligand_bound", + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def prepare_for_group_deposition_upload_ground_state(self): + self.work_thread = XChemDeposit.prepare_for_group_deposition_upload( + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + self.group_deposit_directory, + self.initial_model_directory, + "ground_state", + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def check_smiles_in_db_and_pdb(self): + self.work_thread = XChemDeposit.compare_smiles_in_db_with_ligand_in_pdb( + self.initial_model_directory, + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, QtCore.SIGNAL("show_error_dict"), self.show_error_dict + ) + self.work_thread.start() + + def deposition_data(self): + depositData = QtGui.QMessageBox() + depositDataLayout = depositData.layout() + + vbox = QtGui.QVBoxLayout() + + deposit_tab_widget = QtGui.QTabWidget() + deposit_tab_list = [ + "Contact", + "General", + "Authors", + "Citation", + "Molecule", + "Misc", + "Methods", + "Software", + "Funding", + ] + + deposit_tab_dict = {} + for page in deposit_tab_list: + tab = QtGui.QWidget() + vb = QtGui.QVBoxLayout(tab) + deposit_tab_widget.addTab(tab, page) + deposit_tab_dict[page] = [tab, vb] + + # PI and scientist info + vb = QtGui.QVBoxLayout() + hbox = QtGui.QHBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + grid.addWidget(QtGui.QLabel("Principal Investigator"), 0, 0) + + grid.addWidget(QtGui.QLabel("Salutation"), 1, 0) + self.contact_author_PI_salutation = QtGui.QLineEdit() + self.contact_author_PI_salutation.setText("Dr.") + self.contact_author_PI_salutation.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_salutation, 1, 1) + + grid.addWidget(QtGui.QLabel("First name"), 2, 0) + self.contact_author_PI_first_name = QtGui.QLineEdit() + self.contact_author_PI_first_name.setText("") + self.contact_author_PI_first_name.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_first_name, 2, 1) + + grid.addWidget(QtGui.QLabel("Last name"), 3, 0) + self.contact_author_PI_last_name = QtGui.QLineEdit() + self.contact_author_PI_last_name.setText("") + self.contact_author_PI_last_name.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_last_name, 3, 1) + + grid.addWidget(QtGui.QLabel("Middle name"), 4, 0) + self.contact_author_PI_middle_name = QtGui.QLineEdit() + self.contact_author_PI_middle_name.setText("") + self.contact_author_PI_middle_name.setFixedWidth(200) + self.contact_author_PI_middle_name.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.contact_author_PI_middle_name, 4, 1) + + grid.addWidget(QtGui.QLabel("PI role"), 5, 0) + self.contact_author_PI_role = QtGui.QComboBox() + PIroles = ["principal investigator/group leader"] + for item in PIroles: + self.contact_author_PI_role.addItem(item) + grid.addWidget(self.contact_author_PI_role, 5, 1) + + grid.addWidget(QtGui.QLabel("Organization type"), 6, 0) + self.contact_author_PI_organization_type = QtGui.QComboBox() + Organizations = ["academic", "commercial", "government"] + for item in Organizations: + self.contact_author_PI_organization_type.addItem(item) + grid.addWidget(self.contact_author_PI_organization_type, 6, 1) + + grid.addWidget(QtGui.QLabel("Organization Name"), 7, 0) + self.contact_author_PI_organization_name = QtGui.QLineEdit() + self.contact_author_PI_organization_name.setText("") + self.contact_author_PI_organization_name.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_organization_name, 7, 1) + + grid.addWidget(QtGui.QLabel("Email"), 8, 0) + self.contact_author_PI_email = QtGui.QLineEdit() + self.contact_author_PI_email.setText("") + self.contact_author_PI_email.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_email, 8, 1) + + grid.addWidget(QtGui.QLabel("Street"), 9, 0) + self.contact_author_PI_address = QtGui.QLineEdit() + self.contact_author_PI_address.setText("") + self.contact_author_PI_address.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_address, 9, 1) + + grid.addWidget(QtGui.QLabel("City"), 10, 0) + self.contact_author_PI_city = QtGui.QLineEdit() + self.contact_author_PI_city.setText("") + self.contact_author_PI_city.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_city, 10, 1) + + grid.addWidget(QtGui.QLabel("State"), 11, 0) + self.contact_author_PI_State_or_Province = QtGui.QLineEdit() + self.contact_author_PI_State_or_Province.setText("") + self.contact_author_PI_State_or_Province.setFixedWidth(200) + self.contact_author_PI_State_or_Province.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.contact_author_PI_State_or_Province, 11, 1) + + grid.addWidget(QtGui.QLabel("ZIP code"), 12, 0) + self.contact_author_PI_Zip_Code = QtGui.QLineEdit() + self.contact_author_PI_Zip_Code.setText("") + self.contact_author_PI_Zip_Code.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_Zip_Code, 12, 1) + + grid.addWidget(QtGui.QLabel("Country"), 13, 0) + self.contact_author_PI_Country = QtGui.QLineEdit() + self.contact_author_PI_Country.setText("") + self.contact_author_PI_Country.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_Country, 13, 1) + + grid.addWidget(QtGui.QLabel("Phone"), 14, 0) + self.contact_author_PI_phone_number = QtGui.QLineEdit() + self.contact_author_PI_phone_number.setText("") + self.contact_author_PI_phone_number.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_phone_number, 14, 1) + + grid.addWidget(QtGui.QLabel("ORCID"), 15, 0) + self.contact_author_PI_ORCID = QtGui.QLineEdit() + self.contact_author_PI_ORCID.setText("") + self.contact_author_PI_ORCID.setFixedWidth(200) + grid.addWidget(self.contact_author_PI_ORCID, 15, 1) + + frame.setLayout(grid) + hbox.addWidget(frame) + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + grid = QtGui.QGridLayout() + grid.addWidget(QtGui.QLabel("Responsible Scientist"), 0, 0) + + grid.addWidget(QtGui.QLabel("Salutation"), 1, 0) + self.contact_author_salutation = QtGui.QLineEdit() + self.contact_author_salutation.setText("Dr.") + self.contact_author_salutation.setFixedWidth(200) + grid.addWidget(self.contact_author_salutation, 1, 1) + + grid.addWidget(QtGui.QLabel("First name"), 2, 0) + self.contact_author_first_name = QtGui.QLineEdit() + self.contact_author_first_name.setText("") + self.contact_author_first_name.setFixedWidth(200) + grid.addWidget(self.contact_author_first_name, 2, 1) + + grid.addWidget(QtGui.QLabel("Last name"), 3, 0) + self.contact_author_last_name = QtGui.QLineEdit() + self.contact_author_last_name.setText("") + self.contact_author_last_name.setFixedWidth(200) + grid.addWidget(self.contact_author_last_name, 3, 1) + + grid.addWidget(QtGui.QLabel("Middle name"), 4, 0) + self.contact_author_middle_name = QtGui.QLineEdit() + self.contact_author_middle_name.setText("") + self.contact_author_middle_name.setFixedWidth(200) + self.contact_author_middle_name.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.contact_author_middle_name, 4, 1) + + grid.addWidget(QtGui.QLabel("Role"), 5, 0) + + self.contact_author_role = QtGui.QComboBox() + ScientistRoles = ["responsible scientist", "investigator"] + for item in ScientistRoles: + self.contact_author_role.addItem(item) + grid.addWidget(self.contact_author_role, 5, 1) + + grid.addWidget(QtGui.QLabel("Organization type"), 6, 0) + + self.contact_author_organization_type = QtGui.QComboBox() + for item in Organizations: + self.contact_author_organization_type.addItem(item) + grid.addWidget(self.contact_author_organization_type, 6, 1) + + grid.addWidget(QtGui.QLabel("Organization Name"), 7, 0) + self.contact_author_organization_name = QtGui.QLineEdit() + self.contact_author_organization_name.setText("") + self.contact_author_organization_name.setFixedWidth(200) + grid.addWidget(self.contact_author_organization_name, 7, 1) + + grid.addWidget(QtGui.QLabel("Email"), 8, 0) + self.contact_author_email = QtGui.QLineEdit() + self.contact_author_email.setText("") + self.contact_author_email.setFixedWidth(200) + grid.addWidget(self.contact_author_email, 8, 1) + + grid.addWidget(QtGui.QLabel("Street"), 9, 0) + self.contact_author_address = QtGui.QLineEdit() + self.contact_author_address.setText("") + self.contact_author_address.setFixedWidth(200) + grid.addWidget(self.contact_author_address, 9, 1) + + grid.addWidget(QtGui.QLabel("City"), 10, 0) + self.contact_author_city = QtGui.QLineEdit() + self.contact_author_city.setText("") + self.contact_author_city.setFixedWidth(200) + grid.addWidget(self.contact_author_city, 10, 1) + + grid.addWidget(QtGui.QLabel("State"), 11, 0) + self.contact_author_State_or_Province = QtGui.QLineEdit() + self.contact_author_State_or_Province.setText("") + self.contact_author_State_or_Province.setFixedWidth(200) + self.contact_author_State_or_Province.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.contact_author_State_or_Province, 11, 1) + + grid.addWidget(QtGui.QLabel("ZIP code"), 12, 0) + self.contact_author_Zip_Code = QtGui.QLineEdit() + self.contact_author_Zip_Code.setText("") + self.contact_author_Zip_Code.setFixedWidth(200) + grid.addWidget(self.contact_author_Zip_Code, 12, 1) + + grid.addWidget(QtGui.QLabel("Country"), 13, 0) + self.contact_author_Country = QtGui.QLineEdit() + self.contact_author_Country.setText("") + self.contact_author_Country.setFixedWidth(200) + grid.addWidget(self.contact_author_Country, 13, 1) + + grid.addWidget(QtGui.QLabel("Phone"), 14, 0) + self.contact_author_phone_number = QtGui.QLineEdit() + self.contact_author_phone_number.setText("") + self.contact_author_phone_number.setFixedWidth(200) + grid.addWidget(self.contact_author_phone_number, 14, 1) + + grid.addWidget(QtGui.QLabel("ORCID"), 15, 0) + self.contact_author_ORCID = QtGui.QLineEdit() + self.contact_author_ORCID.setText("") + self.contact_author_ORCID.setFixedWidth(200) + grid.addWidget(self.contact_author_ORCID, 15, 1) + + frame.setLayout(grid) + hbox.addWidget(frame) + + vb.addLayout(hbox) + vb.addWidget(QtGui.QLabel(XChemToolTips.deposition_interface_note())) + vb.addStretch(1) + + deposit_tab_dict["Contact"][1].addLayout(vb) + + # release status + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + grid.addWidget(QtGui.QLabel("Release status"), 0, 0) + + grid.addWidget(QtGui.QLabel("Release Status for sequence"), 4, 0) + + self.Release_status_for_sequence = QtGui.QComboBox() + codeStatus = ["RELEASE NOW", "HOLD FOR RELEASE"] + for item in codeStatus: + self.Release_status_for_sequence.addItem(item) + grid.addWidget(self.Release_status_for_sequence, 4, 1) + + grid.addWidget(QtGui.QLabel("Release Status for coordinates/ SF"), 8, 0) + self.Release_status_for_coordinates = QtGui.QComboBox() + coordStatus = [ + "RELEASE NOW", + "HOLD FOR PUBLICATION", + "HOLD FOR 4 WEEKS", + "HOLD FOR 6 MONTHS", + "HOLD FOR 1 YEAR", + ] + for item in coordStatus: + self.Release_status_for_coordinates.addItem(item) + grid.addWidget(self.Release_status_for_coordinates, 8, 1) + + frame.setLayout(grid) + vb.addWidget(frame) + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + grid.addWidget(QtGui.QLabel("Title & Details"), 0, 0) + note = ( + "Note: supported wildcards: $ProteinName,$CompoundName;" + ' e.g. "Crystal Structure of human JMJD2D in complex with N2317a"' + ) + grid.addWidget(QtGui.QLabel(note), 1, 0) + + grid.addWidget(QtGui.QLabel("Group deposition title"), 2, 0) + self.group_deposition_title = QtGui.QLineEdit() + self.group_deposition_title.setText("PanDDA analysis group deposition") + self.group_deposition_title.setFixedWidth(600) + + grid.addWidget(self.group_deposition_title, 2, 1) + + grid.addWidget(QtGui.QLabel("Description"), 3, 0) + self.group_description = QtGui.QLineEdit() + self.group_description.setText( + "XDomainX of XOrganismX $ProteinName screened against the" + " XXX Fragment Library by X-ray Crystallography at the XChem facility of" + " Diamond Light Source beamline I04-1" + ) + self.group_description.setFixedWidth(600) + grid.addWidget(self.group_description, 3, 1) + + grid.addWidget(QtGui.QLabel("Structure Title (ligand bound)"), 4, 0) + self.structure_title = QtGui.QLineEdit() + self.structure_title.setText( + "Crystal Structure of $ProteinName in complex with $CompoundName" + ) + self.structure_title.setFixedWidth(600) + grid.addWidget(self.structure_title, 4, 1) + + note = "\n\nApo Structure:\nonly use if you want to deposit PanDDA models!" + grid.addWidget(QtGui.QLabel(note), 6, 0) + + grid.addWidget(QtGui.QLabel("Structure Title (apo)"), 7, 0) + self.structure_title_apo = QtGui.QLineEdit() + self.structure_title_apo.setText( + "PanDDA analysis group deposition of ground-state model of $ProteinName" + ) + self.structure_title_apo.setFixedWidth(600) + grid.addWidget(self.structure_title_apo, 7, 1) + + frame.setLayout(grid) + vb.addWidget(frame) + + vb.addStretch(1) + + deposit_tab_dict["General"][1].addLayout(vb) + + # authors + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + grid.addWidget(QtGui.QLabel("Deposition authors (e.g. Surname, F.M.)"), 0, 0) + + self.structure_author_name_List = [] + + for column in range(0, 2): + for row in range(1, 15): + structure_author_name = QtGui.QLineEdit() + structure_author_name.setText("") + structure_author_name.setFixedWidth(300) + grid.addWidget(structure_author_name, row, column) + self.structure_author_name_List.append(structure_author_name) + + frame.setLayout(grid) + vb.addWidget(frame) + + vb.addStretch(1) + + deposit_tab_dict["Authors"][1].addLayout(vb) + + # primary citation + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + grid.addWidget(QtGui.QLabel("Primary Citation"), 0, 0) + + grid.addWidget(QtGui.QLabel("ID"), 1, 0) + self.primary_citation_id = QtGui.QLineEdit() + self.primary_citation_id.setText("primary") + self.primary_citation_id.setFixedWidth(500) + grid.addWidget(self.primary_citation_id, 1, 1) + + grid.addWidget(QtGui.QLabel("Journal"), 2, 0) + self.primary_citation_journal_abbrev = QtGui.QLineEdit() + self.primary_citation_journal_abbrev.setText("To be published") + self.primary_citation_journal_abbrev.setFixedWidth(500) + grid.addWidget(self.primary_citation_journal_abbrev, 2, 1) + + grid.addWidget(QtGui.QLabel("Title"), 3, 0) + self.primary_citation_title = QtGui.QLineEdit() + self.primary_citation_title.setText("") + self.primary_citation_title.setFixedWidth(500) + self.primary_citation_title.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.primary_citation_title, 3, 1) + + grid.addWidget(QtGui.QLabel("Year"), 4, 0) + self.primary_citation_year = QtGui.QLineEdit() + self.primary_citation_year.setText("") + self.primary_citation_year.setFixedWidth(500) + self.primary_citation_year.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.primary_citation_year, 4, 1) + + grid.addWidget(QtGui.QLabel("Volume"), 5, 0) + self.primary_citation_journal_volume = QtGui.QLineEdit() + self.primary_citation_journal_volume.setText("") + self.primary_citation_journal_volume.setFixedWidth(500) + self.primary_citation_journal_volume.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.primary_citation_journal_volume, 5, 1) + + grid.addWidget(QtGui.QLabel("Page, first"), 6, 0) + self.primary_citation_page_first = QtGui.QLineEdit() + self.primary_citation_page_first.setText("") + self.primary_citation_page_first.setFixedWidth(500) + self.primary_citation_page_first.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.primary_citation_page_first, 6, 1) + + grid.addWidget(QtGui.QLabel("Page, last"), 7, 0) + self.primary_citation_page_last = QtGui.QLineEdit() + self.primary_citation_page_last.setText("") + self.primary_citation_page_last.setFixedWidth(500) + self.primary_citation_page_last.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.primary_citation_page_last, 7, 1) + + frame.setLayout(grid) + vb.addWidget(frame) + + # citation authors + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + self.set_primary_citation_authors = QtGui.QCheckBox( + "same as deposition authors" + ) + layout_functions.add_checkbox( + self, + self.set_primary_citation_authors, + "xce_object.set_primary_citation_as_structure_authors", + ) + grid.addWidget(self.set_primary_citation_authors, 0, 0) + + self.primary_citation_author_name_List = [] + + for column in range(0, 2): + for row in range(1, 15): + primary_citation_author_name = QtGui.QLineEdit() + primary_citation_author_name.setText("") + primary_citation_author_name.setFixedWidth(300) + grid.addWidget(primary_citation_author_name, row, column) + self.primary_citation_author_name_List.append( + primary_citation_author_name + ) + + frame.setLayout(grid) + vb.addWidget(frame) + + vb.addStretch(1) + + deposit_tab_dict["Citation"][1].addLayout(vb) + + # molecule info + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("Entity 1"), 1, 0) + + grid.addWidget(QtGui.QLabel("Molecule Name"), 2, 0) + self.molecule_name = QtGui.QLineEdit() + self.molecule_name.setText("") + self.molecule_name.setFixedWidth(300) + + grid.addWidget(self.molecule_name, 2, 1) + grid.addWidget(QtGui.QLabel("(e.g. RNA Hammerhead Ribozyme)"), 2, 2) + + grid.addWidget(QtGui.QLabel("Fragment Name"), 3, 0) + self.fragment_name_one = QtGui.QLineEdit() + self.fragment_name_one.setText("") + self.fragment_name_one.setFixedWidth(300) + self.fragment_name_one.setStyleSheet("background-color: rgb(192, 192, 192);") + grid.addWidget(self.fragment_name_one, 3, 1) + grid.addWidget(QtGui.QLabel("(e.g. ligand binding domain, hairpin)"), 3, 2) + + grid.addWidget(QtGui.QLabel("Specific Mutation"), 4, 0) + self.fragment_name_one_specific_mutation = QtGui.QLineEdit() + self.fragment_name_one_specific_mutation.setText("") + self.fragment_name_one_specific_mutation.setFixedWidth(300) + self.fragment_name_one_specific_mutation.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.fragment_name_one_specific_mutation, 4, 1) + grid.addWidget(QtGui.QLabel("(e.g. C280S)"), 4, 2) + + grid.addWidget(QtGui.QLabel("Enzyme Comission Number"), 5, 0) + self.fragment_name_one_enzyme_comission_number = QtGui.QLineEdit() + self.fragment_name_one_enzyme_comission_number.setText("") + self.fragment_name_one_enzyme_comission_number.setFixedWidth(300) + self.fragment_name_one_enzyme_comission_number.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.fragment_name_one_enzyme_comission_number, 5, 1) + grid.addWidget(QtGui.QLabel("(if known: e.g. 2.7.7.7)"), 5, 2) + + grid.addWidget(QtGui.QLabel("Genetically Manipulated Source"), 6, 0) + + grid.addWidget(QtGui.QLabel("Source organism scientific name"), 7, 0) + + self.Source_organism_scientific_name = QtGui.QComboBox() + taxonomy_dict = XChemMain.NCBI_taxonomy_ID() + for item in taxonomy_dict: + self.Source_organism_scientific_name.addItem(taxonomy_dict[item]) + grid.addWidget(self.Source_organism_scientific_name, 7, 1) + + grid.addWidget(QtGui.QLabel("Source organism gene"), 8, 0) + self.Source_organism_gene = QtGui.QLineEdit() + self.Source_organism_gene.setText("") + self.Source_organism_gene.setFixedWidth(300) + grid.addWidget(self.Source_organism_gene, 8, 1) + grid.addWidget(QtGui.QLabel("(e.g. RPOD, ALKA...)"), 8, 2) + + grid.addWidget(QtGui.QLabel("Source organism strain"), 9, 0) + self.Source_organism_strain = QtGui.QLineEdit() + self.Source_organism_strain.setText("") + self.Source_organism_strain.setFixedWidth(300) + self.Source_organism_strain.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Source_organism_strain, 9, 1) + grid.addWidget(QtGui.QLabel("(e.g. BH10 ISOLATE, K-12...)"), 9, 2) + + grid.addWidget(QtGui.QLabel("Expression system scientific name"), 10, 0) + + self.Expression_system_scientific_name = QtGui.QComboBox() + for item in taxonomy_dict: + self.Expression_system_scientific_name.addItem(taxonomy_dict[item]) + grid.addWidget(self.Expression_system_scientific_name, 10, 1) + + grid.addWidget(QtGui.QLabel("Expression system strain"), 11, 0) + self.Expression_system_strain = QtGui.QLineEdit() + self.Expression_system_strain.setText("") + self.Expression_system_strain.setFixedWidth(300) + self.Expression_system_strain.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Expression_system_strain, 11, 1) + grid.addWidget(QtGui.QLabel("(e.g. BL21(DE3))"), 11, 2) + + grid.addWidget(QtGui.QLabel("Expression system vector type"), 12, 0) + self.Expression_system_vector_type = QtGui.QLineEdit() + self.Expression_system_vector_type.setText("") + self.Expression_system_vector_type.setFixedWidth(300) + self.Expression_system_vector_type.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Expression_system_vector_type, 12, 1) + grid.addWidget(QtGui.QLabel("(e.g. plasmid)"), 12, 2) + + grid.addWidget(QtGui.QLabel("Expression_system_plasmid_name"), 13, 0) + self.Expression_system_plasmid_name = QtGui.QLineEdit() + self.Expression_system_plasmid_name.setText("") + self.Expression_system_plasmid_name.setFixedWidth(300) + self.Expression_system_plasmid_name.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Expression_system_plasmid_name, 13, 1) + grid.addWidget(QtGui.QLabel("(e.g. pET26)"), 13, 2) + + grid.addWidget(QtGui.QLabel("Manipulated_source_details"), 14, 0) + self.Manipulated_source_details = QtGui.QLineEdit() + self.Manipulated_source_details.setText("") + self.Manipulated_source_details.setFixedWidth(300) + self.Manipulated_source_details.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Manipulated_source_details, 14, 1) + grid.addWidget(QtGui.QLabel("(any other relevant information)"), 14, 2) + + grid.addWidget(QtGui.QLabel("Chains"), 15, 0) + self.molecule_chain_one = QtGui.QLineEdit() + self.molecule_chain_one.setText("") + self.molecule_chain_one.setFixedWidth(300) + grid.addWidget(self.molecule_chain_one, 15, 1) + grid.addWidget(QtGui.QLabel("(e.g. A or A,B)"), 15, 2) + + frame.setLayout(grid) + vb.addWidget(frame) + + # entity 2 + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget( + QtGui.QLabel( + "Entity 2 (IMPORTANT: only fill in if you are working with a" + " protein-protein complex!)" + ), + 1, + 0, + ) + + grid.addWidget(QtGui.QLabel("Molecule Name"), 2, 0) + self.molecule_name_two = QtGui.QLineEdit() + self.molecule_name_two.setText("") + self.molecule_name_two.setFixedWidth(300) + + grid.addWidget(self.molecule_name_two, 2, 1) + grid.addWidget(QtGui.QLabel("(e.g. RNA Hammerhead Ribozyme)"), 2, 2) + + grid.addWidget(QtGui.QLabel("Fragment Name"), 3, 0) + self.fragment_name_two = QtGui.QLineEdit() + self.fragment_name_two.setText("") + self.fragment_name_two.setFixedWidth(300) + self.fragment_name_two.setStyleSheet("background-color: rgb(192, 192, 192);") + grid.addWidget(self.fragment_name_two, 3, 1) + grid.addWidget(QtGui.QLabel("(e.g. ligand binding domain, hairpin)"), 3, 2) + + grid.addWidget(QtGui.QLabel("Specific Mutation"), 4, 0) + self.fragment_name_two_specific_mutation = QtGui.QLineEdit() + self.fragment_name_two_specific_mutation.setText("") + self.fragment_name_two_specific_mutation.setFixedWidth(300) + self.fragment_name_two_specific_mutation.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.fragment_name_two_specific_mutation, 4, 1) + grid.addWidget(QtGui.QLabel("(e.g. C280S)"), 4, 2) + + grid.addWidget(QtGui.QLabel("Enzyme Comission Number"), 5, 0) + self.fragment_name_two_enzyme_comission_number = QtGui.QLineEdit() + self.fragment_name_two_enzyme_comission_number.setText("") + self.fragment_name_two_enzyme_comission_number.setFixedWidth(300) + self.fragment_name_two_enzyme_comission_number.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.fragment_name_two_enzyme_comission_number, 5, 1) + grid.addWidget(QtGui.QLabel("(if known: e.g. 2.7.7.7)"), 5, 2) + + grid.addWidget(QtGui.QLabel("Genetically Manipulated Source"), 6, 0) + + grid.addWidget(QtGui.QLabel("Source organism scientific name"), 7, 0) + + self.Source_organism_scientific_name_two = QtGui.QComboBox() + taxonomy_dict = XChemMain.NCBI_taxonomy_ID() + for item in taxonomy_dict: + self.Source_organism_scientific_name_two.addItem(taxonomy_dict[item]) + grid.addWidget(self.Source_organism_scientific_name_two, 7, 1) + + grid.addWidget(QtGui.QLabel("Source organism gene"), 8, 0) + self.Source_organism_gene_two = QtGui.QLineEdit() + self.Source_organism_gene_two.setText("") + self.Source_organism_gene_two.setFixedWidth(300) + grid.addWidget(self.Source_organism_gene_two, 8, 1) + grid.addWidget(QtGui.QLabel("(e.g. RPOD, ALKA...)"), 8, 2) + + grid.addWidget(QtGui.QLabel("Source organism strain"), 9, 0) + self.Source_organism_strain_two = QtGui.QLineEdit() + self.Source_organism_strain_two.setText("") + self.Source_organism_strain_two.setFixedWidth(300) + self.Source_organism_strain_two.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Source_organism_strain_two, 9, 1) + grid.addWidget(QtGui.QLabel("(e.g. BH10 ISOLATE, K-12...)"), 9, 2) + + grid.addWidget(QtGui.QLabel("Expression system scientific name"), 10, 0) + + self.Expression_system_scientific_name_two = QtGui.QComboBox() + for item in taxonomy_dict: + self.Expression_system_scientific_name_two.addItem(taxonomy_dict[item]) + grid.addWidget(self.Expression_system_scientific_name_two, 10, 1) + + grid.addWidget(QtGui.QLabel("Expression system strain"), 11, 0) + self.Expression_system_strain_two = QtGui.QLineEdit() + self.Expression_system_strain_two.setText("") + self.Expression_system_strain_two.setFixedWidth(300) + self.Expression_system_strain_two.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Expression_system_strain_two, 11, 1) + grid.addWidget(QtGui.QLabel("(e.g. BL21(DE3))"), 11, 2) + + grid.addWidget(QtGui.QLabel("Expression system vector type"), 12, 0) + self.Expression_system_vector_type_two = QtGui.QLineEdit() + self.Expression_system_vector_type_two.setText("") + self.Expression_system_vector_type_two.setFixedWidth(300) + self.Expression_system_vector_type_two.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Expression_system_vector_type_two, 12, 1) + grid.addWidget(QtGui.QLabel("(e.g. plasmid)"), 12, 2) + + grid.addWidget(QtGui.QLabel("Expression_system_plasmid_name"), 13, 0) + self.Expression_system_plasmid_name_two = QtGui.QLineEdit() + self.Expression_system_plasmid_name_two.setText("") + self.Expression_system_plasmid_name_two.setFixedWidth(300) + self.Expression_system_plasmid_name_two.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Expression_system_plasmid_name_two, 13, 1) + grid.addWidget(QtGui.QLabel("(e.g. pET26)"), 13, 2) + + grid.addWidget(QtGui.QLabel("Manipulated_source_details"), 14, 0) + self.Manipulated_source_details_two = QtGui.QLineEdit() + self.Manipulated_source_details_two.setText("") + self.Manipulated_source_details_two.setFixedWidth(300) + self.Manipulated_source_details_two.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + grid.addWidget(self.Manipulated_source_details_two, 14, 1) + grid.addWidget(QtGui.QLabel("(any other relevant information)"), 14, 2) + + grid.addWidget(QtGui.QLabel("Chains"), 15, 0) + self.molecule_chain_two = QtGui.QLineEdit() + self.molecule_chain_two.setText("") + self.molecule_chain_two.setFixedWidth(300) + grid.addWidget(self.molecule_chain_two, 15, 1) + grid.addWidget(QtGui.QLabel("(e.g. A or A,B)"), 15, 2) + + frame.setLayout(grid) + + vb.addWidget(frame) + + # entity 2 --- END + + vb.addStretch(1) + + deposit_tab_dict["Molecule"][1].addLayout(vb) + + # misc + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("Keywords"), 1, 0) + self.structure_keywords = QtGui.QLineEdit() + self.structure_keywords.setText( + "SGC - Diamond I04-1 fragment screening, PanDDA, XChemExplorer" + ) + self.structure_keywords.setFixedWidth(300) + grid.addWidget(self.structure_keywords, 1, 1) + grid.addWidget(QtGui.QLabel("(e.g. beta barrel, protein-DNA complex)"), 1, 2) + + grid.addWidget(QtGui.QLabel("Type"), 2, 0) + self.structure_keywords_type = QtGui.QComboBox() + self.structure_keywords_type.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + for item in XChemMain.pdbx_keywords(): + self.structure_keywords_type.addItem(item) + grid.addWidget(self.structure_keywords_type, 2, 1) + + grid.addWidget(QtGui.QLabel("Biological Assembly"), 3, 0) + self.biological_assembly_chain_number = QtGui.QLineEdit() + self.biological_assembly_chain_number.setText("") + self.biological_assembly_chain_number.setFixedWidth(300) + grid.addWidget(self.biological_assembly_chain_number, 3, 1) + grid.addWidget(QtGui.QLabel("(e.g. 1 for monomer, 2 for dimer ..)"), 3, 2) + + grid.addWidget(QtGui.QLabel("Sequence UNIPROT ID"), 4, 0) + self.molecule_one_letter_sequence_uniprot_id = QtGui.QLineEdit() + self.molecule_one_letter_sequence_uniprot_id.setText("") + self.molecule_one_letter_sequence_uniprot_id.setFixedWidth(300) + grid.addWidget(self.molecule_one_letter_sequence_uniprot_id, 4, 1) + grid.addWidget(QtGui.QLabel("(e.g. Q6B0I6)"), 4, 2) + + grid.addWidget(QtGui.QLabel("Sequence"), 5, 0) + self.molecule_one_letter_sequence = QtGui.QTextEdit() + self.molecule_one_letter_sequence.setStyleSheet( + "background-color: rgb(255, 255, 255);" + ) + + self.molecule_one_letter_sequence.setText("") + self.molecule_one_letter_sequence.setFixedWidth(300) + grid.addWidget(self.molecule_one_letter_sequence, 5, 1, 8, 2) + + grid.addWidget(QtGui.QLabel("Sequence UNIPROT ID (Entity 2) - optional"), 13, 0) + self.molecule_one_letter_sequence_uniprot_id_two = QtGui.QLineEdit() + self.molecule_one_letter_sequence_uniprot_id_two.setText("") + self.molecule_one_letter_sequence_uniprot_id_two.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + self.molecule_one_letter_sequence_uniprot_id_two.setFixedWidth(300) + grid.addWidget(self.molecule_one_letter_sequence_uniprot_id_two, 13, 1) + grid.addWidget(QtGui.QLabel("(e.g. Q6B0I6)"), 13, 2) + + grid.addWidget(QtGui.QLabel("Sequence (Entity 2) - optional"), 14, 0) + self.molecule_one_letter_sequence_two = QtGui.QTextEdit() + self.molecule_one_letter_sequence_two.setText("") + self.molecule_one_letter_sequence_two.setFixedWidth(300) + grid.addWidget(self.molecule_one_letter_sequence_two, 14, 1, 19, 2) + + grid.addWidget(QtGui.QLabel("Structural Genomic (optional)"), 21, 0) + + grid.addWidget(QtGui.QLabel("Project Name"), 22, 0) + self.SG_project_name = QtGui.QLineEdit() + self.SG_project_name.setText("") + self.SG_project_name.setStyleSheet("background-color: rgb(192, 192, 192);") + self.SG_project_name.setFixedWidth(300) + grid.addWidget(self.SG_project_name, 22, 1) + grid.addWidget( + QtGui.QLabel("(e.g. SGC, Structural Genomics Consortium)"), 22, 2 + ) + + grid.addWidget(QtGui.QLabel("Full Name"), 23, 0) + self.full_name_of_SG_center = QtGui.QLineEdit() + self.full_name_of_SG_center.setText("") + self.full_name_of_SG_center.setStyleSheet( + "background-color: rgb(192, 192, 192);" + ) + self.full_name_of_SG_center.setFixedWidth(300) + grid.addWidget(self.full_name_of_SG_center, 23, 1) + grid.addWidget(QtGui.QLabel("(e.g. Structural Genomics Consortium)"), 23, 2) + + frame.setLayout(grid) + vb.addWidget(frame) + + vb.addStretch(1) + + deposit_tab_dict["Misc"][1].addLayout(vb) + + # methods + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("Crystallization"), 1, 0) + + grid.addWidget(QtGui.QLabel("Method"), 2, 0) + + self.crystallization_method = QtGui.QComboBox() + for item in XChemMain.crystal_growth_methods(): + self.crystallization_method.addItem(item) + grid.addWidget(self.crystallization_method, 2, 1) + + grid.addWidget(QtGui.QLabel("pH"), 3, 0) + self.crystallization_pH = QtGui.QLineEdit() + self.crystallization_pH.setText("") + self.crystallization_pH.setFixedWidth(300) + grid.addWidget(self.crystallization_pH, 3, 1) + grid.addWidget(QtGui.QLabel("(e.g. 7.5 ...)"), 3, 2) + + grid.addWidget(QtGui.QLabel("Temperature"), 4, 0) + self.crystallization_temperature = QtGui.QLineEdit() + self.crystallization_temperature.setText("") + self.crystallization_temperature.setFixedWidth(300) + grid.addWidget(self.crystallization_temperature, 4, 1) + grid.addWidget(QtGui.QLabel("(e.g. 298) (in Kelvin)"), 4, 2) + + grid.addWidget(QtGui.QLabel("Condition"), 5, 0) + self.crystallization_details = QtGui.QLineEdit() + self.crystallization_details.setText("") + self.crystallization_details.setFixedWidth(300) + grid.addWidget(self.crystallization_details, 5, 1) + grid.addWidget(QtGui.QLabel("(e.g. PEG 4000, NaCl etc.)"), 5, 2) + + grid.addWidget(QtGui.QLabel("Diffraction Experiment"), 6, 0) + note = ( + "Note: this information will only be used if it is\n" + "not already available in the mainTable!\n" + "Ignore if data were collected at DLS" + ) + grid.addWidget(QtGui.QLabel(note), 7, 0) + + grid.addWidget(QtGui.QLabel("Source"), 8, 0) + + self.radiation_source = QtGui.QComboBox() + for item in XChemMain.radiationSource(): + self.radiation_source.addItem(item) + grid.addWidget(self.radiation_source, 8, 1) + + grid.addWidget(QtGui.QLabel("Source Type"), 9, 0) + + self.radiation_source_type = QtGui.QComboBox() + for item in XChemMain.wwBeamlines(): + self.radiation_source_type.addItem(item) + grid.addWidget(self.radiation_source_type, 9, 1) + + grid.addWidget(QtGui.QLabel("Wavelength"), 10, 0) + self.radiation_wavelengths = QtGui.QLineEdit() + self.radiation_wavelengths.setText("") + self.radiation_wavelengths.setFixedWidth(300) + grid.addWidget(self.radiation_wavelengths, 10, 1) + grid.addWidget(QtGui.QLabel("(e.g. 1.502)"), 10, 2) + + grid.addWidget(QtGui.QLabel("Detector"), 11, 0) + + self.radiation_detector = QtGui.QComboBox() + for item in XChemMain.detector(): + self.radiation_detector.addItem(item) + grid.addWidget(self.radiation_detector, 11, 1) + + grid.addWidget(QtGui.QLabel("Detector Type"), 12, 0) + + self.radiation_detector_type = QtGui.QComboBox() + for item in XChemMain.detectorType(): + self.radiation_detector_type.addItem(item) + grid.addWidget(self.radiation_detector_type, 12, 1) + + grid.addWidget(QtGui.QLabel("Date"), 13, 0) + self.data_collection_date = QtGui.QLineEdit() + self.data_collection_date.setText("") + self.data_collection_date.setFixedWidth(300) + grid.addWidget(self.data_collection_date, 13, 1) + grid.addWidget(QtGui.QLabel("(e.g. 2004-01-07)"), 13, 2) + + grid.addWidget(QtGui.QLabel("Temperature"), 14, 0) + self.data_collection_temperature = QtGui.QLineEdit() + self.data_collection_temperature.setText("") + self.data_collection_temperature.setFixedWidth(300) + grid.addWidget(self.data_collection_temperature, 14, 1) + grid.addWidget(QtGui.QLabel("(e.g. 100) (in Kelvin)"), 14, 2) + + grid.addWidget(QtGui.QLabel("Protocol"), 15, 0) + self.data_collection_protocol = QtGui.QLineEdit() + self.data_collection_protocol.setText("SINGLE WAVELENGTH") + self.data_collection_protocol.setFixedWidth(300) + grid.addWidget(self.data_collection_protocol, 15, 1) + grid.addWidget(QtGui.QLabel("(e.g. SINGLE WAVELENGTH, MAD, ...)"), 15, 2) + + frame.setLayout(grid) + vb.addWidget(frame) + + vb.addStretch(1) + + deposit_tab_dict["Methods"][1].addLayout(vb) + + # software + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("PDB starting model"), 1, 0) + self.pdbx_starting_model = QtGui.QLineEdit() + self.pdbx_starting_model.setText("") + self.pdbx_starting_model.setFixedWidth(300) + grid.addWidget(self.pdbx_starting_model, 1, 1) + grid.addWidget(QtGui.QLabel("(e.g. 7.5 ...)"), 1, 2) + + grid.addWidget(QtGui.QLabel("Data reduction"), 2, 0) + self.data_integration_software = QtGui.QComboBox() + for item in XChemMain.data_integration_software(): + self.data_integration_software.addItem(item) + grid.addWidget(self.data_integration_software, 2, 1) + + grid.addWidget(QtGui.QLabel("Phasing"), 3, 0) + self.phasing_software = QtGui.QComboBox() + for item in XChemMain.phasing_software(): + self.phasing_software.addItem(item) + grid.addWidget(self.phasing_software, 3, 1) + + frame.setLayout(grid) + vb.addWidget(frame) + vb.addStretch(1) + + deposit_tab_dict["Software"][1].addLayout(vb) + + # Funding + + vb = QtGui.QVBoxLayout() + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("Funding Organization"), 1, 0) + self.pdbx_funding_organization_one = QtGui.QLineEdit() + self.pdbx_funding_organization_one.setText("") + self.pdbx_funding_organization_one.setFixedWidth(700) + grid.addWidget(self.pdbx_funding_organization_one, 1, 1) + + grid.addWidget(QtGui.QLabel("Grant Number"), 2, 0) + self.pdbx_grant_number_one = QtGui.QLineEdit() + self.pdbx_grant_number_one.setText("") + self.pdbx_grant_number_one.setFixedWidth(700) + grid.addWidget(self.pdbx_grant_number_one, 2, 1) + + grid.addWidget(QtGui.QLabel("Country"), 3, 0) + self.pdbx_grant_country_one = QtGui.QComboBox() + for item in XChemMain.pdbx_country(): + self.pdbx_grant_country_one.addItem(item) + grid.addWidget(self.pdbx_grant_country_one, 3, 1) + + frame.setLayout(grid) + vb.addWidget(frame) + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("Funding Organization"), 1, 0) + self.pdbx_funding_organization_two = QtGui.QLineEdit() + self.pdbx_funding_organization_two.setText("") + self.pdbx_funding_organization_two.setFixedWidth(700) + grid.addWidget(self.pdbx_funding_organization_two, 1, 1) + + grid.addWidget(QtGui.QLabel("Grant Number"), 2, 0) + self.pdbx_grant_number_two = QtGui.QLineEdit() + self.pdbx_grant_number_two.setText("") + self.pdbx_grant_number_two.setFixedWidth(700) + grid.addWidget(self.pdbx_grant_number_two, 2, 1) + + grid.addWidget(QtGui.QLabel("Country"), 3, 0) + self.pdbx_grant_country_two = QtGui.QComboBox() + for item in XChemMain.pdbx_country(): + self.pdbx_grant_country_two.addItem(item) + grid.addWidget(self.pdbx_grant_country_two, 3, 1) + + frame.setLayout(grid) + vb.addWidget(frame) + + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + + grid = QtGui.QGridLayout() + + grid.addWidget(QtGui.QLabel("Funding Organization"), 1, 0) + self.pdbx_funding_organization_three = QtGui.QLineEdit() + self.pdbx_funding_organization_three.setText("") + self.pdbx_funding_organization_three.setFixedWidth(700) + grid.addWidget(self.pdbx_funding_organization_three, 1, 1) + + grid.addWidget(QtGui.QLabel("Grant Number"), 2, 0) + self.pdbx_grant_number_three = QtGui.QLineEdit() + self.pdbx_grant_number_three.setText("") + self.pdbx_grant_number_three.setFixedWidth(700) + grid.addWidget(self.pdbx_grant_number_three, 2, 1) + + grid.addWidget(QtGui.QLabel("Country"), 3, 0) + self.pdbx_grant_country_three = QtGui.QComboBox() + for item in XChemMain.pdbx_country(): + self.pdbx_grant_country_three.addItem(item) + grid.addWidget(self.pdbx_grant_country_three, 3, 1) + + frame.setLayout(grid) + vb.addWidget(frame) + + vb.addStretch(1) + + deposit_tab_dict["Funding"][1].addLayout(vb) + + vbox.addWidget(deposit_tab_widget) + + hbox = QtGui.QHBoxLayout() + button = QtGui.QPushButton("Load\nFile") + button.clicked.connect(self.load_deposit_config_file) + hbox.addWidget(button) + button = QtGui.QPushButton("Save\nFile") + button.clicked.connect(self.save_deposit_config_file) + hbox.addWidget(button) + button = QtGui.QPushButton("Load from\nDatabase") + button.clicked.connect(self.load_deposit_from_database) + button.setEnabled(False) + hbox.addWidget(button) + button = QtGui.QPushButton("Save to\nDatabase") + button.clicked.connect(self.save_deposit_to_database) + hbox.addWidget(button) + + vbox.addLayout(hbox) + depositDataLayout.addLayout(vbox, 0, 0) + + depositData.exec_() + + def save_deposit_config_file(self): + self.update_deposit_dict() + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, "Save file", self.current_directory + ) + ) + # make sure that the file always has .deposit extension + if str(file_name).rfind(".") != -1: + file_name = file_name[: file_name.rfind(".")] + ".deposit" + else: + file_name = file_name + ".deposit" + pickle.dump(self.deposit_dict, open(file_name, "wb")) + + def update_database_with_pdb_codes(self): + self.work_thread = XChemDeposit.import_PDB_IDs( + str(self.pdb_code_entry.toPlainText()), + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def update_database_with_labelInfo(self): + for n, l in enumerate(self.labelList): + label = str(l[0].text()) + description = str(l[1].text()) + + self.db.execute_statement( + "update labelTable set Label='%s',Description='%s' where ID=%s" + % (label, description, str(n + 1)) + ) + + def load_deposit_config_file(self): + file_name_temp = QtGui.QFileDialog.getOpenFileNameAndFilter( + self.window, "Open file", self.current_directory, "*.deposit" + ) + file_name = tuple(file_name_temp)[0] + self.deposit_dict = pickle.load(open(file_name, "rb")) + + for key in self.get_deposit_dict_template(): + if key not in self.deposit_dict: + self.update_log.warning("field not in .deposit file: " + str(key)) + self.deposit_dict[key] = "" + self.update_deposit_input() + + def load_deposit_from_database(self): + print("hallo") + + def save_deposit_to_database(self): + self.update_deposit_dict() + msgBox = QtGui.QMessageBox() + msgBox.setText( + "*** WARNING ***\n" + "Are you sure you want to update the database?\n" + "This will overwrite previous entries!" + ) + msgBox.addButton(QtGui.QPushButton("Yes"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("No"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + if reply == 0: + self.work_thread = XChemDeposit.update_depositTable( + self.deposit_dict, + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def update_deposit_input(self): + try: + self.contact_author_PI_salutation.setText( + self.deposit_dict["contact_author_PI_salutation"] + ) + self.contact_author_PI_first_name.setText( + self.deposit_dict["contact_author_PI_first_name"] + ) + self.contact_author_PI_last_name.setText( + self.deposit_dict["contact_author_PI_last_name"] + ) + self.contact_author_PI_middle_name.setText( + self.deposit_dict["contact_author_PI_middle_name"] + ) + index = self.contact_author_PI_role.findText( + self.deposit_dict["contact_author_PI_role"], QtCore.Qt.MatchFixedString + ) + self.contact_author_PI_role.setCurrentIndex(index) + index = self.contact_author_PI_organization_type.findText( + self.deposit_dict["contact_author_PI_organization_type"], + QtCore.Qt.MatchFixedString, + ) + self.contact_author_PI_organization_type.setCurrentIndex(index) + self.contact_author_PI_organization_name.setText( + self.deposit_dict["contact_author_PI_organization_name"] + ) + self.contact_author_PI_email.setText( + self.deposit_dict["contact_author_PI_email"] + ) + self.contact_author_PI_address.setText( + self.deposit_dict["contact_author_PI_address"] + ) + self.contact_author_PI_city.setText( + self.deposit_dict["contact_author_PI_city"] + ) + self.contact_author_PI_State_or_Province.setText( + self.deposit_dict["contact_author_PI_State_or_Province"] + ) + self.contact_author_PI_Zip_Code.setText( + self.deposit_dict["contact_author_PI_Zip_Code"] + ) + self.contact_author_PI_Country.setText( + self.deposit_dict["contact_author_PI_Country"] + ) + self.contact_author_PI_phone_number.setText( + self.deposit_dict["contact_author_PI_phone_number"] + ) + self.contact_author_PI_ORCID.setText( + self.deposit_dict["contact_author_PI_ORCID"] + ) + + self.contact_author_salutation.setText( + self.deposit_dict["contact_author_salutation"] + ) + self.contact_author_first_name.setText( + self.deposit_dict["contact_author_first_name"] + ) + self.contact_author_last_name.setText( + self.deposit_dict["contact_author_last_name"] + ) + self.contact_author_middle_name.setText( + self.deposit_dict["contact_author_middle_name"] + ) + index = self.contact_author_role.findText( + self.deposit_dict["contact_author_role"], QtCore.Qt.MatchFixedString + ) + self.contact_author_role.setCurrentIndex(index) + index = self.contact_author_organization_type.findText( + self.deposit_dict["contact_author_organization_type"], + QtCore.Qt.MatchFixedString, + ) + self.contact_author_organization_type.setCurrentIndex(index) + self.contact_author_organization_name.setText( + self.deposit_dict["contact_author_organization_name"] + ) + self.contact_author_email.setText(self.deposit_dict["contact_author_email"]) + self.contact_author_address.setText( + self.deposit_dict["contact_author_address"] + ) + self.contact_author_city.setText(self.deposit_dict["contact_author_city"]) + self.contact_author_State_or_Province.setText( + self.deposit_dict["contact_author_State_or_Province"] + ) + self.contact_author_Zip_Code.setText( + self.deposit_dict["contact_author_Zip_Code"] + ) + self.contact_author_Country.setText( + self.deposit_dict["contact_author_Country"] + ) + self.contact_author_phone_number.setText( + self.deposit_dict["contact_author_phone_number"] + ) + self.contact_author_ORCID.setText(self.deposit_dict["contact_author_ORCID"]) + index = self.Release_status_for_coordinates.findText( + self.deposit_dict["Release_status_for_coordinates"], + QtCore.Qt.MatchFixedString, + ) + self.Release_status_for_coordinates.setCurrentIndex(index) + index = self.Release_status_for_sequence.findText( + self.deposit_dict["Release_status_for_sequence"], + QtCore.Qt.MatchFixedString, + ) + self.Release_status_for_sequence.setCurrentIndex(index) + + self.group_deposition_title.setText( + self.deposit_dict["group_deposition_title"] + ) + self.group_description.setText(self.deposit_dict["group_description"]) + + self.structure_title.setText(self.deposit_dict["structure_title"]) + self.structure_title_apo.setText(self.deposit_dict["structure_title_apo"]) + + for n, name in enumerate( + self.deposit_dict["structure_author_name"].split(";") + ): + self.structure_author_name_List[n].setText(name) + + self.primary_citation_id.setText(self.deposit_dict["primary_citation_id"]) + self.primary_citation_journal_abbrev.setText( + self.deposit_dict["primary_citation_journal_abbrev"] + ) + self.primary_citation_title.setText( + self.deposit_dict["primary_citation_title"] + ) + self.primary_citation_year.setText( + self.deposit_dict["primary_citation_year"] + ) + self.primary_citation_journal_volume.setText( + self.deposit_dict["primary_citation_journal_volume"] + ) + self.primary_citation_page_first.setText( + self.deposit_dict["primary_citation_page_first"] + ) + self.primary_citation_page_last.setText( + self.deposit_dict["primary_citation_page_last"] + ) + + for n, name in enumerate( + self.deposit_dict["primary_citation_author_name"].split(";") + ): + self.primary_citation_author_name_List[n].setText(name) + + # entity 1 + + self.molecule_name.setText(self.deposit_dict["molecule_name"]) + self.fragment_name_one_specific_mutation.setText( + self.deposit_dict["fragment_name_one_specific_mutation"] + ) + index = self.Source_organism_scientific_name.findText( + self.deposit_dict["Source_organism_scientific_name"], + QtCore.Qt.MatchFixedString, + ) + self.Source_organism_scientific_name.setCurrentIndex(index) + + self.Source_organism_gene.setText(self.deposit_dict["Source_organism_gene"]) + self.Source_organism_strain.setText( + self.deposit_dict["Source_organism_strain"] + ) + index = self.Expression_system_scientific_name.findText( + self.deposit_dict["Expression_system_scientific_name"], + QtCore.Qt.MatchFixedString, + ) + self.Expression_system_scientific_name.setCurrentIndex(index) + + self.Expression_system_strain.setText( + self.deposit_dict["Expression_system_strain"] + ) + self.Expression_system_vector_type.setText( + self.deposit_dict["Expression_system_vector_type"] + ) + self.Expression_system_plasmid_name.setText( + self.deposit_dict["Expression_system_plasmid_name"] + ) + self.Manipulated_source_details.setText( + self.deposit_dict["Manipulated_source_details"] + ) + + self.molecule_chain_one.setText(self.deposit_dict["molecule_chain_one"]) + # entity 2 + self.molecule_name_two.setText(self.deposit_dict["molecule_name_two"]) + self.fragment_name_two_specific_mutation.setText( + self.deposit_dict["fragment_name_two_specific_mutation"] + ) + index = self.Source_organism_scientific_name_two.findText( + self.deposit_dict["Source_organism_scientific_name_two"], + QtCore.Qt.MatchFixedString, + ) + self.Source_organism_scientific_name_two.setCurrentIndex(index) + self.Source_organism_gene_two.setText( + self.deposit_dict["Source_organism_gene_two"] + ) + self.Source_organism_strain_two.setText( + self.deposit_dict["Source_organism_strain_two"] + ) + index = self.Expression_system_scientific_name_two.findText( + self.deposit_dict["Expression_system_scientific_name_two"], + QtCore.Qt.MatchFixedString, + ) + self.Expression_system_scientific_name_two.setCurrentIndex(index) + + self.Expression_system_strain_two.setText( + self.deposit_dict["Expression_system_strain_two"] + ) + self.Expression_system_vector_type_two.setText( + self.deposit_dict["Expression_system_vector_type_two"] + ) + self.Expression_system_plasmid_name_two.setText( + self.deposit_dict["Expression_system_plasmid_name_two"] + ) + self.Manipulated_source_details_two.setText( + self.deposit_dict["Manipulated_source_details_two"] + ) + self.molecule_chain_two.setText(self.deposit_dict["molecule_chain_two"]) + self.molecule_one_letter_sequence_uniprot_id_two.setText( + self.deposit_dict["molecule_two_letter_sequence_uniprot_id"] + ) + self.molecule_one_letter_sequence_two.setText( + self.deposit_dict["molecule_two_letter_sequence"] + ) + + self.structure_keywords.setText(self.deposit_dict["structure_keywords"]) + self.biological_assembly_chain_number.setText( + self.deposit_dict["biological_assembly_chain_number"] + ) + self.molecule_one_letter_sequence_uniprot_id.setText( + self.deposit_dict["molecule_one_letter_sequence_uniprot_id"] + ) + self.molecule_one_letter_sequence.setText( + self.deposit_dict["molecule_one_letter_sequence"] + ) + self.SG_project_name.setText(self.deposit_dict["SG_project_name"]) + self.full_name_of_SG_center.setText( + self.deposit_dict["full_name_of_SG_center"] + ) + + index = self.crystallization_method.findText( + self.deposit_dict["crystallization_method"], QtCore.Qt.MatchFixedString + ) + self.crystallization_method.setCurrentIndex(index) + + self.crystallization_pH.setText(self.deposit_dict["crystallization_pH"]) + self.crystallization_temperature.setText( + self.deposit_dict["crystallization_temperature"] + ) + self.crystallization_details.setText( + self.deposit_dict["crystallization_details"] + ) + index = self.radiation_source.findText( + self.deposit_dict["radiation_source"], QtCore.Qt.MatchFixedString + ) + self.radiation_source.setCurrentIndex(index) + + index = self.radiation_source_type.findText( + self.deposit_dict["radiation_source_type"], QtCore.Qt.MatchFixedString + ) + self.radiation_source_type.setCurrentIndex(index) + + self.radiation_wavelengths.setText( + self.deposit_dict["radiation_wavelengths"] + ) + index = self.radiation_detector.findText( + self.deposit_dict["radiation_detector"], QtCore.Qt.MatchFixedString + ) + self.radiation_detector.setCurrentIndex(index) + + index = self.radiation_detector_type.findText( + self.deposit_dict["radiation_detector_type"], QtCore.Qt.MatchFixedString + ) + self.radiation_detector_type.setCurrentIndex(index) + + self.data_collection_date.setText(self.deposit_dict["data_collection_date"]) + self.data_collection_temperature.setText( + self.deposit_dict["data_collection_temperature"] + ) + self.data_collection_protocol.setText( + self.deposit_dict["data_collection_protocol"] + ) + + self.pdbx_starting_model.setText(self.deposit_dict["pdbx_starting_model"]) + index = self.data_integration_software.findText( + self.deposit_dict["data_integration_software"], + QtCore.Qt.MatchFixedString, + ) + self.data_integration_software.setCurrentIndex(index) + index = self.phasing_software.findText( + self.deposit_dict["phasing_software"], QtCore.Qt.MatchFixedString + ) + self.phasing_software.setCurrentIndex(index) + + self.pdbx_funding_organization_one.setText( + self.deposit_dict["pdbx_funding_organization_one"] + ) + self.pdbx_grant_number_one.setText( + self.deposit_dict["pdbx_grant_number_one"] + ) + index = self.pdbx_grant_country_one.findText( + self.deposit_dict["pdbx_grant_country_one"], QtCore.Qt.MatchFixedString + ) + self.pdbx_grant_country_one.setCurrentIndex(index) + + self.pdbx_funding_organization_two.setText( + self.deposit_dict["pdbx_funding_organization_two"] + ) + self.pdbx_grant_number_two.setText( + self.deposit_dict["pdbx_grant_number_two"] + ) + index = self.pdbx_grant_country_two.findText( + self.deposit_dict["pdbx_grant_country_two"], QtCore.Qt.MatchFixedString + ) + self.pdbx_grant_country_two.setCurrentIndex(index) + + self.pdbx_funding_organization_three.setText( + self.deposit_dict["pdbx_funding_organization_three"] + ) + self.pdbx_grant_number_three.setText( + self.deposit_dict["pdbx_grant_number_three"] + ) + index = self.pdbx_grant_country_three.findText( + self.deposit_dict["pdbx_grant_country_three"], + QtCore.Qt.MatchFixedString, + ) + self.pdbx_grant_country_three.setCurrentIndex(index) + + except ValueError as e: + self.update_log.error("file is not a valid .deposit file: " + str(e)) + + def update_deposit_dict(self): + pdbx_funding_ordinal_one = "" + pdbx_funding_organization_one = "" + pdbx_grant_number_one = "" + pdbx_grant_country_one = "" + if str(self.pdbx_funding_organization_one.text()).replace(" ", "") != "": + pdbx_funding_ordinal_one = "1" + pdbx_funding_organization_one = str( + self.pdbx_funding_organization_one.text() + ) + pdbx_grant_number_one = str(self.pdbx_grant_number_one.text()) + pdbx_grant_country_one = str(self.pdbx_grant_country_one.currentText()) + + pdbx_funding_ordinal_two = "" + pdbx_funding_organization_two = "" + pdbx_grant_number_two = "" + pdbx_grant_country_two = "" + if str(self.pdbx_funding_organization_two.text()).replace(" ", "") != "": + pdbx_funding_ordinal_two = "2" + pdbx_funding_organization_two = str( + self.pdbx_funding_organization_two.text() + ) + pdbx_grant_number_two = str(self.pdbx_grant_number_two.text()) + pdbx_grant_country_two = str(self.pdbx_grant_country_two.currentText()) + + pdbx_funding_ordinal_three = "" + pdbx_funding_organization_three = "" + pdbx_grant_number_three = "" + pdbx_grant_country_three = "" + if str(self.pdbx_funding_organization_three.text()).replace(" ", "") != "": + pdbx_funding_ordinal_three = "3" + pdbx_funding_organization_three = str( + self.pdbx_funding_organization_three.text() + ) + pdbx_grant_number_three = str(self.pdbx_grant_number_three.text()) + pdbx_grant_country_three = str(self.pdbx_grant_country_three.currentText()) + + self.deposit_dict = { + "contact_author_PI_salutation": str( + self.contact_author_PI_salutation.text() + ), + "contact_author_PI_first_name": str( + self.contact_author_PI_first_name.text() + ), + "contact_author_PI_last_name": str(self.contact_author_PI_last_name.text()), + "contact_author_PI_middle_name": str( + self.contact_author_PI_middle_name.text() + ), + "contact_author_PI_role": str(self.contact_author_PI_role.currentText()), + "contact_author_PI_organization_type": str( + self.contact_author_PI_organization_type.currentText() + ), + "contact_author_PI_organization_name": str( + self.contact_author_PI_organization_name.text() + ), + "contact_author_PI_email": str(self.contact_author_PI_email.text()), + "contact_author_PI_address": str(self.contact_author_PI_address.text()), + "contact_author_PI_city": str(self.contact_author_PI_city.text()), + "contact_author_PI_State_or_Province": str( + self.contact_author_PI_State_or_Province.text() + ), + "contact_author_PI_Zip_Code": str(self.contact_author_PI_Zip_Code.text()), + "contact_author_PI_Country": str(self.contact_author_PI_Country.text()), + "contact_author_PI_phone_number": str( + self.contact_author_PI_phone_number.text() + ), + "contact_author_PI_ORCID": str(self.contact_author_PI_ORCID.text()), + "contact_author_salutation": str(self.contact_author_salutation.text()), + "contact_author_first_name": str(self.contact_author_first_name.text()), + "contact_author_last_name": str(self.contact_author_last_name.text()), + "contact_author_middle_name": str(self.contact_author_middle_name.text()), + "contact_author_role": str(self.contact_author_role.currentText()), + "contact_author_organization_type": str( + self.contact_author_organization_type.currentText() + ), + "contact_author_organization_name": str( + self.contact_author_organization_name.text() + ), + "contact_author_email": str(self.contact_author_email.text()), + "contact_author_address": str(self.contact_author_address.text()), + "contact_author_city": str(self.contact_author_city.text()), + "contact_author_State_or_Province": str( + self.contact_author_State_or_Province.text() + ), + "contact_author_Zip_Code": str(self.contact_author_Zip_Code.text()), + "contact_author_Country": str(self.contact_author_Country.text()), + "contact_author_phone_number": str(self.contact_author_phone_number.text()), + "contact_author_ORCID": str(self.contact_author_ORCID.text()), + "Release_status_for_coordinates": str( + self.Release_status_for_coordinates.currentText() + ), + "Release_status_for_sequence": str( + self.Release_status_for_sequence.currentText() + ), + "group_deposition_title": str(self.group_deposition_title.text()), + "group_description": str(self.group_description.text()), + "structure_title": str(self.structure_title.text()), + "structure_title_apo": str(self.structure_title_apo.text()), + "primary_citation_id": str(self.primary_citation_id.text()), + "primary_citation_journal_abbrev": str( + self.primary_citation_journal_abbrev.text() + ), + "primary_citation_title": str(self.primary_citation_title.text()), + "primary_citation_year": str(self.primary_citation_year.text()), + "primary_citation_journal_volume": str( + self.primary_citation_journal_volume.text() + ), + "primary_citation_page_first": str(self.primary_citation_page_first.text()), + "primary_citation_page_last": str(self.primary_citation_page_last.text()), + # entity 1 + "molecule_name": str(self.molecule_name.text()), + "Source_organism_scientific_name": str( + self.Source_organism_scientific_name.currentText() + ), + "Source_organism_gene": str(self.Source_organism_gene.text()), + "Source_organism_strain": str(self.Source_organism_strain.text()), + "Expression_system_scientific_name": str( + self.Expression_system_scientific_name.currentText() + ), + "Expression_system_strain": str(self.Expression_system_strain.text()), + "Expression_system_plasmid_name": str( + self.Expression_system_plasmid_name.text() + ), + "Expression_system_vector_type": str( + self.Expression_system_vector_type.text() + ), + "Manipulated_source_details": str(self.Manipulated_source_details.text()), + "fragment_name_one_specific_mutation": str( + self.fragment_name_one_specific_mutation.text() + ), + "molecule_chain_one": str(self.molecule_chain_one.text()), + # entity 2 + "molecule_name_two": str(self.molecule_name_two.text()), + "Source_organism_scientific_name_two": str( + self.Source_organism_scientific_name_two.currentText() + ), + "Source_organism_gene_two": str(self.Source_organism_gene_two.text()), + "Source_organism_strain_two": str(self.Source_organism_strain_two.text()), + "Expression_system_scientific_name_two": str( + self.Expression_system_scientific_name_two.currentText() + ), + "Expression_system_strain_two": str( + self.Expression_system_strain_two.text() + ), + "Expression_system_plasmid_name_two": str( + self.Expression_system_plasmid_name_two.text() + ), + "Expression_system_vector_type_two": str( + self.Expression_system_vector_type_two.text() + ), + "Manipulated_source_details_two": str( + self.Manipulated_source_details_two.text() + ), + "fragment_name_two_specific_mutation": str( + self.fragment_name_two_specific_mutation.text() + ), + "molecule_chain_two": str(self.molecule_chain_two.text()), + "structure_keywords": str(self.structure_keywords.text()), + "biological_assembly_chain_number": str( + self.biological_assembly_chain_number.text() + ), + "molecule_one_letter_sequence_uniprot_id": str( + self.molecule_one_letter_sequence_uniprot_id.text() + ), + "molecule_two_letter_sequence_uniprot_id": str( + self.molecule_one_letter_sequence_uniprot_id_two.text() + ), + "SG_project_name": str(self.SG_project_name.text()), + "full_name_of_SG_center": str(self.full_name_of_SG_center.text()), + "molecule_one_letter_sequence": str( + self.molecule_one_letter_sequence.toPlainText() + ) + .replace(" ", "") + .replace("\n", "") + .replace("\r", ""), + "molecule_two_letter_sequence": str( + self.molecule_one_letter_sequence_two.toPlainText() + ) + .replace(" ", "") + .replace("\n", "") + .replace("\r", ""), + "crystallization_method": str(self.crystallization_method.currentText()), + "crystallization_pH": str(self.crystallization_pH.text()), + "crystallization_temperature": str(self.crystallization_temperature.text()), + "crystallization_details": str(self.crystallization_details.text()), + "radiation_source": str(self.radiation_source.currentText()), + "radiation_source_type": str(self.radiation_source_type.currentText()), + "radiation_wavelengths": str(self.radiation_wavelengths.text()), + "radiation_detector": str(self.radiation_detector.currentText()), + "radiation_detector_type": str(self.radiation_detector_type.currentText()), + "data_collection_date": str(self.data_collection_date.text()), + "data_collection_temperature": str(self.data_collection_temperature.text()), + "data_collection_protocol": str(self.data_collection_protocol.text()), + "pdbx_starting_model": str(self.pdbx_starting_model.text()), + "data_integration_software": str( + self.data_integration_software.currentText() + ), + "phasing_software": str(self.phasing_software.currentText()), + "pdbx_funding_ordinal_one": pdbx_funding_ordinal_one, + "pdbx_funding_organization_one": pdbx_funding_organization_one, + "pdbx_grant_number_one": pdbx_grant_number_one, + "pdbx_grant_country_one": pdbx_grant_country_one, + "pdbx_funding_ordinal_two": pdbx_funding_ordinal_two, + "pdbx_funding_organization_two": pdbx_funding_organization_two, + "pdbx_grant_number_two": pdbx_grant_number_two, + "pdbx_grant_country_two": pdbx_grant_country_two, + "pdbx_funding_ordinal_three": pdbx_funding_ordinal_three, + "pdbx_funding_organization_three": pdbx_funding_organization_three, + "pdbx_grant_number_three": pdbx_grant_number_three, + "pdbx_grant_country_three": pdbx_grant_country_three, + } + + structure_author_name = "" + for widget in self.structure_author_name_List: + structure_author_name += str(widget.text()) + ";" + self.deposit_dict["structure_author_name"] = structure_author_name[:-1] + + primary_citation_author_name = "" + for widget in self.primary_citation_author_name_List: + primary_citation_author_name += str(widget.text()) + ";" + self.deposit_dict[ + "primary_citation_author_name" + ] = primary_citation_author_name[:-1] + + def get_deposit_dict_template(self): + deposit_dict_template = { + "contact_author_PI_salutation": None, + "contact_author_PI_first_name": None, + "contact_author_PI_last_name": None, + "contact_author_PI_middle_name": None, + "contact_author_PI_role": None, + "contact_author_PI_organization_type": None, + "contact_author_PI_organization_name": None, + "contact_author_PI_email": None, + "contact_author_PI_address": None, + "contact_author_PI_city": None, + "contact_author_PI_State_or_Province": None, + "contact_author_PI_Zip_Code": None, + "contact_author_PI_Country": None, + "contact_author_PI_phone_number": None, + "contact_author_PI_ORCID": None, + "contact_author_salutation": None, + "contact_author_first_name": None, + "contact_author_last_name": None, + "contact_author_middle_name": None, + "contact_author_role": None, + "contact_author_organization_type": None, + "contact_author_organization_name": None, + "contact_author_email": None, + "contact_author_address": None, + "contact_author_city": None, + "contact_author_State_or_Province": None, + "contact_author_Zip_Code": None, + "contact_author_Country": None, + "contact_author_phone_number": None, + "contact_author_ORCID": None, + "Release_status_for_coordinates": None, + "Release_status_for_sequence": None, + "group_deposition_title": None, + "group_description": None, + "structure_title": None, + "structure_title_apo": None, + "primary_citation_id": None, + "primary_citation_journal_abbrev": None, + "primary_citation_title": None, + "primary_citation_year": None, + "primary_citation_journal_volume": None, + "primary_citation_page_first": None, + "primary_citation_page_last": None, + # entity 1 + "molecule_name": None, + "Source_organism_scientific_name": None, + "Source_organism_gene": None, + "Source_organism_strain": None, + "Expression_system_scientific_name": None, + "Expression_system_strain": None, + "Expression_system_plasmid_name": None, + "Expression_system_vector_type": None, + "Manipulated_source_details": None, + "fragment_name_one_specific_mutation": None, + "molecule_chain_one": None, + # entity 2 + "molecule_name_two": None, + "Source_organism_scientific_name_two": None, + "Source_organism_gene_two": None, + "Source_organism_strain_two": None, + "Expression_system_scientific_name_two": None, + "Expression_system_strain_two": None, + "Expression_system_plasmid_name_two": None, + "Expression_system_vector_type_two": None, + "Manipulated_source_details_two": None, + "fragment_name_two_specific_mutation": None, + "molecule_chain_two": None, + "structure_keywords": None, + "biological_assembly_chain_number": None, + "molecule_one_letter_sequence_uniprot_id": None, + "molecule_two_letter_sequence_uniprot_id": None, + "SG_project_name": None, + "full_name_of_SG_center": None, + "molecule_one_letter_sequence": None, + "molecule_two_letter_sequence": None, + "crystallization_method": None, + "crystallization_pH": None, + "crystallization_temperature": None, + "crystallization_details": None, + "radiation_source": None, + "radiation_source_type": None, + "radiation_wavelengths": None, + "radiation_detector": None, + "radiation_detector_type": None, + "data_collection_date": None, + "data_collection_temperature": None, + "data_collection_protocol": None, + "pdbx_starting_model": None, + "data_integration_software": None, + "phasing_software": None, + "structure_author_name": None, + "primary_citation_author_name": None, + "pdbx_funding_organization_one": "", + "pdbx_grant_number_one": "", + "pdbx_grant_country_one": "", + "pdbx_funding_organization_two": "", + "pdbx_grant_number_two": "", + "pdbx_grant_country_two": "", + "pdbx_funding_organization_three": "", + "pdbx_grant_number_three": "", + "pdbx_grant_country_three": "", + } + + return deposit_dict_template + + def set_primary_citation_as_structure_authors(self, state): + if state == QtCore.Qt.Checked: + for n, entry in enumerate(self.structure_author_name_List): + self.primary_citation_author_name_List[n].setText(str(entry.text())) + else: + for n, entry in enumerate(self.primary_citation_author_name_List): + entry.setText("") + + def set_xce_logfile(self): + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, "Save file", self.current_directory + ) + ) + self.xce_logfile = str(file_name) + self.xce_logfile_label.setText(str(self.xce_logfile)) + if ( + self.xce_logfile == "" + or self.xce_logfile[self.xce_logfile.rfind("/") + 1 :] == "" + ): + print("==> XCE: invalid file format") + else: + XChemLog.startLog(self.xce_logfile).create_logfile(self.xce_version) + self.update_log = XChemLog.updateLog(self.xce_logfile) + + def set_second_cif_file(self): + filepath_temp = QtGui.QFileDialog.getOpenFileNameAndFilter( + self.window, "Select CIF File", self.initial_model_directory, "*.cif" + ) + filepath = str(tuple(filepath_temp)[0]) + self.second_cif_file = str(filepath) + self.second_cif_file_label.setText(str(self.second_cif_file)) + self.update_log.insert( + "user selected %s as CIF file for merging into ligand CIF files" + % self.second_cif_file + ) + + def select_datasource_columns_to_display(self): + columns_to_show = QtGui.QMessageBox() + columns_to_showLayout = columns_to_show.layout() + columns_in_data_source = self.db.return_column_list() + try: + columns_in_data_source = self.db.return_column_list() + except AttributeError: + print("==> XCE: please select a datasource file") + self.status_bar.showMessage("please select a datasource file") + return + + column_dict = {} + vbox = QtGui.QVBoxLayout() + number_of_entries = len(columns_in_data_source) + columns_shown_in_dialog_column = 15 + grid = QtGui.QGridLayout() + x = 0 + y = 0 + columns_to_ignore = self.db.columns_not_to_display() + for entries_added in range(number_of_entries): + if not columns_in_data_source[entries_added][1] in columns_to_ignore: + data_source_column = QtGui.QCheckBox( + columns_in_data_source[entries_added][1] + ) + column_dict[entries_added] = data_source_column + if ( + columns_in_data_source[entries_added][1] + in self.overview_datasource_table_columns + ): + data_source_column.setChecked(True) + grid.addWidget(data_source_column, y, x) + y += 1 + if y == columns_shown_in_dialog_column: + y = 0 + x += 1 + vbox.addLayout(grid) + columns_to_showLayout.addLayout(vbox, 0, 0) + + columns_to_show.addButton(QtGui.QPushButton("OK"), QtGui.QMessageBox.YesRole) + columns_to_show.addButton( + QtGui.QPushButton("Cancel"), QtGui.QMessageBox.RejectRole + ) + reply = columns_to_show.exec_() + if reply == 0: + columns_to_show_list = ["Sample ID"] + for key in column_dict: + if column_dict[key].isChecked(): + columns_to_show_list.append(columns_in_data_source[key][1]) + self.overview_datasource_table_columns = columns_to_show_list + self.populate_and_update_datasource_table() + + def update_header_and_data_from_datasource(self): + self.update_log.insert( + "getting information for all samples from data source..." + ) + self.db = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ) + self.update_log.insert("creating missing columns in data source") + self.db.create_missing_columns() + self.update_log.insert("load header and data from data source") + self.header, self.data = self.db.load_samples_from_data_source() + self.update_log.insert("get all samples in data source") + + self.xtal_db_dict = {} + sampleID_column = 0 + for n, entry in enumerate(self.header): + if entry == "CrystalName": + sampleID_column = n + break + for line in self.data: + if str(line[sampleID_column]) != "": + db_dict = {} + for n, entry in enumerate(line): + if n != sampleID_column: + db_dict[str(self.header[n])] = str(entry) + self.xtal_db_dict[str(line[sampleID_column])] = db_dict + + print(("==> XCE: found " + str(len(self.xtal_db_dict)) + " samples")) + + def datasource_menu_save_samples(self): + print("hallo") + + def datasource_menu_export_csv_file(self): + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, "Save file", self.database_directory + ) + ) + if file_name.rfind(".") != -1: + file_name = file_name[: file_name.rfind(".")] + ".csv" + else: + file_name = file_name + ".csv" + self.db.export_to_csv_file(file_name) + + def datasource_menu_import_csv_file(self): + if self.data_source_set: + file_name = QtGui.QFileDialog.getOpenFileName( + self.window, "Open file", self.database_directory + ) + self.db.import_csv_file(file_name) + else: + self.update_status_bar("Please load a data source file first") + + def datasource_menu_update_datasource(self): + self.work_thread = XChemThread.synchronise_db_and_filesystem( + self.initial_model_directory, + os.path.join(self.database_directory, self.data_source_file), + self.panddas_directory, + self.xce_logfile, + "project_directory", + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.work_thread.start() + + def export_data_for_WONKA(self): + self.update_log.insert("exporting CSV file for input into WONKA") + self.db.export_csv_for_WONKA() + + def populate_reference_combobox(self, combobox): + combobox.clear() + for reference_file in self.reference_file_list: + combobox.addItem(reference_file[0]) + + def populate_refinement_outcome_combobox(self, combobox): + combobox.clear() + for stage in self.refinement_stage: + combobox.addItem(stage) + + def populate_target_selection_combobox(self, combobox): + combobox.clear() + for target in self.target_list: + combobox.addItem(target) + + def combo_selected(self, text): + self.map_url = str( + self.panddas_directory + + "/analyses/html_summaries/pandda_map_" + + text + + ".html" + ) + self.pandda_maps_html.load(QtCore.QUrl(self.map_url)) + self.pandda_maps_html.show() + + def add_map_html(self): + self.map_list = glob.glob( + str(self.panddas_directory + "/analyses/html_summaries/pandda_map_*.html") + ) + self.list_options = [] + for i in range(0, len(self.map_list)): + string = self.map_list[i] + string = string.replace("/analyses/html_summaries/pandda_map_", "") + string = string.replace(".html", "") + string = string.replace(self.panddas_directory, "") + self.list_options.append(string) + self.pandda_map_list.clear() + for i in range(0, len(self.list_options)): + self.pandda_map_list.addItem(self.list_options[i]) + self.connect( + self.pandda_map_list, + QtCore.SIGNAL("activated(QString)"), + self.combo_selected, + ) + + def open_config_file(self): + file_name_temp = QtGui.QFileDialog.getOpenFileNameAndFilter( + self.window, "Open file", self.current_directory, "*.conf" + ) + file_name = tuple(file_name_temp)[0] + + try: + pickled_settings = pickle.load(open(file_name, "rb")) + except Exception: + print("==> XCE: failed to open config file...") + + key_list = { + "initial_model_directory": "initial_model_directory", + "panddas_directory": "panddas_directory", + "html_export_directory": "html_export_directory", + "group_deposit_directory": "group_deposit_directory", + "database_directory": "database_directory", + "datasets_summary_file": "datasets_summary", + "ccp4_scratch_directory": "ccp4_scratch", + "allowed_unitcell_difference_percent": "unitcell_difference", + "acceptable_low_resolution_limit_for_data": "too_low_resolution_data", + } + + for current_key in key_list: + try: + command = str( + "self." + + current_key + + " = pickled_settings['" + + key_list[current_key] + + "']" + ) + exec(command) + command = str( + 'self.settings["' + + key_list[current_key] + + '"]= self.' + + current_key + ) + exec(command) + print(("==> XCE: found " + key_list[current_key])) + except Exception: + print( + ( + "==> XCE: WARNING: Failed to find settings for: " + + key_list[current_key] + + " Error type: " + + str(sys.exc_info()[0]) + ) + ) + exec(str(current_key + " = ''")) + continue + + try: + pickled_settings = pickle.load(open(file_name, "rb")) + if pickled_settings["beamline_directory"] != self.beamline_directory: + self.beamline_directory = pickled_settings["beamline_directory"] + self.target_list, self.visit_list = XChemMain.get_target_and_visit_list( + self.beamline_directory, self.read_agamemnon.isChecked() + ) + self.settings["beamline_directory"] = self.beamline_directory + self.populate_target_selection_combobox(self.target_selection_combobox) + + layout_functions.pandda_html(self) + self.show_pandda_html_summary() + + self.html_export_directory_label.setText(self.html_export_directory) + + self.group_deposition_directory_label.setText(self.group_deposit_directory) + + self.datasets_summary_file_label.setText(self.datasets_summary_file) + + self.data_source_file = pickled_settings["data_source"] + if self.data_source_file != "": + self.settings["data_source"] = os.path.join( + self.database_directory, self.data_source_file + ) + # this is probably not necessary + if os.path.isfile(self.settings["data_source"]): + write_enabled = self.check_write_permissions_of_data_source() + if not write_enabled: + self.data_source_file_label.setText("") + self.data_source_set = False + else: + self.data_source_file_label.setText( + os.path.join(self.database_directory, self.data_source_file) + ) + self.data_source_set = True + self.db = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ) + self.datasource_menu_reload_samples() + + reference_directory_temp = pickled_settings["reference_directory"] + if reference_directory_temp != self.reference_directory: + self.reference_directory = reference_directory_temp + self.settings["reference_directory"] = self.reference_directory + self.update_reference_files(" ") + for xtal in self.initial_model_dimple_dict: + reference_file_selection_combobox = self.initial_model_dimple_dict[ + xtal + ][1] + self.populate_reference_combobox(reference_file_selection_combobox) + + self.initial_model_directory_label.setText(self.initial_model_directory) + self.panddas_directory_label.setText(self.panddas_directory) + self.pandda_output_data_dir_entry.setText(self.panddas_directory) + self.reference_directory_label.setText(self.reference_directory) + self.beamline_directory_label.setText(self.beamline_directory) + self.ccp4_scratch_directory_label.setText(self.ccp4_scratch_directory) + self.reference_file_list = self.get_reference_file_list(" ") + self.pandda_input_data_dir_entry.setText( + os.path.join(self.initial_model_directory, "*") + ) + + self.update_all_tables() + + except KeyError: + self.update_status_bar("Sorry, this is not a XChemExplorer config file!") + self.update_log.insert("Sorry, this is not a XChemExplorer config file!") + + except Exception as exception: + print(("Unexpected error:", sys.exc_info()[0])) + raise exception + + def save_config_file(self): + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, "Save file", self.current_directory + ) + ) + # make sure that the file always has .conf extension + if str(file_name).rfind(".") != -1: + file_name = file_name[: file_name.rfind(".")] + ".conf" + else: + file_name = file_name + ".conf" + pickle.dump(self.settings, open(file_name, "wb")) + + def update_reference_files(self, reference_root): + self.reference_file_list = self.get_reference_file_list(reference_root) + self.populate_reference_combobox(self.reference_file_selection_combobox) + self.populate_reference_combobox(self.pandda_reference_file_selection_combobox) + + def run_dimple_on_selected_autoprocessing_file(self, instruction): + job_list = [] + for xtal in sorted(self.initial_model_dimple_dict): + if self.initial_model_dimple_dict[xtal][0].isChecked(): + db_dict = self.xtal_db_dict[xtal] + + # the if statement below is so convoluted, so that it is compatible + # with older data source files + + if ( + os.path.isfile( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + ) + or os.path.isfile( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + ) + ) + or os.path.isfile( + os.path.join( + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + ) + or os.path.isfile( + os.path.join(db_dict["DataProcessingPathToMTZfile"]) + ) + ): + if os.path.isfile( + os.path.join( + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + ): + mtzin = os.path.join( + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + elif os.path.isfile( + os.path.join(db_dict["DataProcessingPathToMTZfile"]) + ): + mtzin = os.path.join(db_dict["DataProcessingPathToMTZfile"]) + elif os.path.isfile( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + ): + mtzin = os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + elif os.path.isfile( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + ) + ): + mtzin = os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + ) + + reference_file = str( + self.initial_model_dimple_dict[xtal][1].currentText() + ) + + reference_file_pdb = os.path.join( + self.reference_directory, reference_file + ".pdb" + ) + + if not os.path.isfile(reference_file_pdb): + continue + + if os.path.isfile( + os.path.join(self.reference_directory, reference_file + ".mtz") + ): + reference_file_mtz = " -R " + os.path.join( + self.reference_directory, reference_file + ".mtz" + ) + else: + reference_file_mtz = "" + + if os.path.isfile( + os.path.join(self.reference_directory, reference_file + ".cif") + ): + reference_file_cif = " --libin " + os.path.join( + self.reference_directory, reference_file + ".cif" + ) + else: + reference_file_cif = "" + + job_list.append( + [ + xtal, + "dimple_rerun_on_selected_file", + mtzin, + reference_file_pdb, + reference_file_mtz, + reference_file_cif, + ] + ) + else: + print( + ( + "WARNING: " + + xtal + + " has not been submitted to dimple" + + " because no files were found: " + ) + ) + if not os.path.isfile( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + ): + print( + ( + " " + + str( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + db_dict["DataProcessingMTZfileName"], + ) + ) + + " is missing" + ) + ) + if not os.path.isfile( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + ) + ): + print( + ( + " " + + str( + os.path.join( + db_dict["ProjectDirectory"], + xtal, + db_dict["DataProcessingPathToMTZfile"], + ) + ) + + " is missing" + ) + ) + if not os.path.isfile( + os.path.join(db_dict["DataProcessingPathToMTZfile"]) + ): + print( + ( + " " + + str( + os.path.join(db_dict["DataProcessingPathToMTZfile"]) + + " is missing" + ) + ) + ) + + if job_list: + self.update_log.insert( + "trying to run DIMPLE on SELECTED auto-processing files" + ) + self.check_before_running_dimple(job_list, instruction) + + def remove_selected_dimple_files(self, instruction): + if "dimple" in instruction.lower(): + pipeline = "dimple" + elif "pipedream" in instruction.lower(): + pipeline = "pipedream" + elif "phenix" in instruction.lower(): + pipeline = "phenix.ligand_pipeline" + + job_list = [] + for xtal in sorted(self.initial_model_dimple_dict): + if self.initial_model_dimple_dict[xtal][0].isChecked(): + job_list.append(xtal) + + if job_list: + msgBox = QtGui.QMessageBox() + msgBox.setText( + "Do you really want to delete {0!s} {1!s} files?".format( + len(job_list), self.preferences["initial_refinement_pipeline"] + ) + ) + msgBox.addButton(QtGui.QPushButton("Go"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("Cancel"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + + if reply == 0: + self.status_bar.showMessage( + "preparing to remove {0!s} files".format(pipeline) + ) + self.update_log.insert( + "preparing to remove {0!s} files".format(pipeline) + ) + self.work_thread = XChemThread.remove_selected_dimple_files( + job_list, + self.initial_model_directory, + self.xce_logfile, + self.database_directory, + self.data_source_file, + pipeline, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.work_thread.start() + + def set_results_from_selected_pipeline(self, instruction): + if "dimple" in instruction.lower(): + pipeline = "dimple" + elif "pipedream" in instruction.lower(): + pipeline = "pipedream" + elif "phenix" in instruction.lower(): + pipeline = "phenix.ligand_pipeline" + + self.update_log.warning("selecting initial refinement results from " + pipeline) + + job_list = [] + for xtal in sorted(self.initial_model_dimple_dict): + if self.initial_model_dimple_dict[xtal][0].isChecked(): + job_list.append(xtal) + + self.work_thread = XChemThread.set_results_from_selected_pipeline( + job_list, + self.initial_model_directory, + self.xce_logfile, + self.database_directory, + self.data_source_file, + pipeline, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.work_thread.start() + + def check_before_running_dimple(self, job_list, instruction): + msgBox = QtGui.QMessageBox() + msgBox.setText( + "Do you really want to run {0!s} {1!s} jobs?\nNote: we will not run more" + " than {2!s} at once on the cluster!".format( + len(job_list), + self.preferences["initial_refinement_pipeline"], + self.preferences["max_queue_jobs"], + ) + ) + msgBox.addButton(QtGui.QPushButton("Go"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("Cancel"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + + if reply == 0: + if "dimple" in instruction.lower(): + pipeline = "dimple" + elif "pipedream" in instruction.lower(): + pipeline = "pipedream" + elif "phenix" in instruction.lower(): + pipeline = "phenix.ligand_pipeline" + + self.status_bar.showMessage( + "preparing {0!s} DIMPLE jobs".format(len(job_list)) + ) + self.update_log.insert( + "preparing to run {0!s} DIMPLE jobs".format(len(job_list)) + ) + self.update_log.insert("preparing input files for DIMPLE...") + self.work_thread = XChemThread.run_dimple_on_all_autoprocessing_files_new( + job_list, + self.initial_model_directory, + self.external_software, + self.ccp4_scratch_directory, + self.database_directory, + self.data_source_file, + self.max_queue_jobs, + self.xce_logfile, + self.preferences["dimple_twin_mode"], + pipeline, + get_token(fetch_password_qt), + ) + self.explorer_active = 1 + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.work_thread.start() + + def update_all_tables(self): + self.update_log.insert("checking for new reference files") + self.update_status_bar("checking for new reference files") + self.reference_file_list = self.get_reference_file_list(" ") + self.update_log.insert("updating Overview table") + self.update_status_bar("updating Overview table") + self.populate_and_update_datasource_table() + self.update_log.insert("updating Maps table") + self.update_status_bar("updating Maps table") + self.create_maps_table() + self.update_log.insert("updating PANDDA table") + self.update_status_bar("updating PANDDA table") + self.populate_pandda_analyse_input_table() + self.update_log.insert("updating REFINEMENT table") + self.update_status_bar("updating REFINEMENT table") + self.populate_and_update_refinement_table() + self.update_status_bar("idle") + self.update_summary_plot() + + def change_allowed_unitcell_difference_percent(self, text): + try: + self.allowed_unitcell_difference_percent = int(text) + self.settings[ + "unitcell_difference" + ] = self.allowed_unitcell_difference_percent + self.update_log.insert( + "changing max allowed unit cell difference between reference and xtal" + " to {0!s} percent".format(self.allowed_unitcell_difference_percent) + ) + except ValueError: + if str(text).find(".") != -1: + self.allowed_unitcell_difference_percent = int( + str(text)[: str(text).find(".")] + ) + self.settings[ + "unitcell_difference" + ] = self.allowed_unitcell_difference_percent + self.update_log.insert( + "changing max allowed unit cell difference between reference and" + " xtal to {0!s} percent".format( + self.allowed_unitcell_difference_percent + ) + ) + else: + pass + + def change_max_queue_jobs(self, text): + try: + self.max_queue_jobs = int(text) + self.settings["max_queue_jobs"] = self.max_queue_jobs + self.update_log.insert( + "changing max number of jobs running simultaneously on DLS cluster to" + " {0!s}".format(self.max_queue_jobs) + ) + except ValueError: + if str(text).find(".") != -1: + self.max_queue_jobs = int(str(text)[: str(text).find(".")]) + self.settings["max_queue_jobs"] = self.max_queue_jobs + self.update_log.insert( + "changing max number of jobs running simultaneously on DLS cluster" + " to {0!s}".format(self.max_queue_jobs) + ) + else: + pass + + def change_acceptable_low_resolution_limit(self, text): + try: + self.acceptable_low_resolution_limit_for_data = float(text) + self.settings[ + "too_low_resolution_data" + ] = self.acceptable_low_resolution_limit_for_data + except ValueError: + pass + + def change_filename_root(self, text): + self.filename_root = str(text) + self.settings["filename_root"] = self.filename_root + + def button_clicked(self): + if not self.data_source_set: + print("sender text bit") + if self.sender().text() == "Create New Data\nSource (SQLite)": + file_name = str( + QtGui.QFileDialog.getSaveFileName( + self.window, "Save file", self.database_directory + ) + ) + # make sure that the file always has .sqlite extension + if file_name.rfind(".") != -1: + file_name = file_name[: file_name.rfind(".")] + ".sqlite" + else: + file_name = file_name + ".sqlite" + self.db = XChemDB.data_source(file_name) + print("==> XCE: creating new data source") + self.db.create_empty_data_source_file() + self.db.create_missing_columns() + if self.data_source_file == "": + self.database_directory = file_name[: file_name.rfind("/")] + self.data_source_file = file_name[file_name.rfind("/") + 1 :] + self.data_source_file_label.setText( + os.path.join(self.database_directory, self.data_source_file) + ) + self.settings["database_directory"] = self.database_directory + self.settings["data_source"] = self.data_source_file + self.data_source_set = True + else: + self.no_data_source_selected() + print("No datasource selected") + pass + + # first find out which of the 'Run' or 'Status' buttons is sending + for item in self.workflow_widget_dict: + for widget in self.workflow_widget_dict[item]: + if widget == self.sender(): + # get index of item in self.workflow; Note this index should be the + # same as the index of the self.main_tab_widget which belongs to + # this task + task_index = self.workflow.index(item) + instruction = str(self.workflow_widget_dict[item][0].currentText()) + print(instruction) + action = str(self.sender().text()) + if self.main_tab_widget.currentIndex() == task_index: + if self.explorer_active == 0 and self.data_source_set is True: + if action == "Run": + self.prepare_and_run_task(instruction) + elif action == "Status": + self.get_status_of_workflow_milestone(instruction) + if os.path.exists( + str(self.panddas_directory + "/pandda.done") + ): + self.pandda_status = "Finished!" + self.pandda_status_label.setStyleSheet( + "color: green" + ) + if os.path.exists( + str(self.panddas_directory + "/pandda.running") + ): + self.pandda_status = "Running..." + self.pandda_status_label.setStyleSheet( + "color: orange" + ) + if os.path.exists( + str(self.panddas_directory + "/pandda.errored") + ): + self.pandda_status = ( + "Error encountered..." + " please check the log files for pandda!" + ) + self.pandda_status_label.setStyleSheet("color: red") + self.pandda_status_label.setText( + str("STATUS: " + self.pandda_status) + ) + else: + self.need_to_switch_main_tab(task_index) + + def get_status_of_workflow_milestone(self, instruction): + # first update all tables + self.datasource_menu_reload_samples() + + cluster_dict = XChemMain.get_jobs_running_on_cluster( + self.external_software, self.xce_logfile, get_token(fetch_password_qt) + ) + + self.update_log.insert("getting status updates...") + + self.status_bar.showMessage( + "please check terminal window for further information" + ) + + self.update_log.insert( + "{0!s} samples are currently in database".format( + str(len(self.xtal_db_dict)) + ) + ) + + if "DIMPLE" in instruction: + XChemMain.print_cluster_status_message( + "dimple", cluster_dict, self.xce_logfile + ) + + elif "Create CIF/PDB/PNG file" in instruction: + XChemMain.print_acedrg_status(self.xce_logfile, self.xtal_db_dict) + XChemMain.print_cluster_status_message( + "acedrg", cluster_dict, self.xce_logfile + ) + + elif instruction.startswith("Run xia2 on selected datasets"): + XChemMain.print_cluster_status_message( + "xia2", cluster_dict, self.xce_logfile + ) + + elif "pandda" in instruction.lower(): + XChemMain.print_cluster_status_message( + "pandda", cluster_dict, self.xce_logfile + ) + + elif "coot" in instruction.lower(): + XChemMain.print_cluster_status_message( + "refmac", cluster_dict, self.xce_logfile + ) + + def prepare_and_run_task(self, instruction): + if instruction == "Get New Results from Autoprocessing": + self.rescore = False + self.check_for_new_autoprocessing_results() + + elif instruction == "Rescore Datasets": + self.rescore = True + self.select_best_autoprocessing_result() + + elif instruction == "Run DIMPLE on selected MTZ files": + self.run_dimple_on_selected_autoprocessing_file(instruction) + + elif instruction == "Run PIPEDREAM on selected MTZ files": + self.run_dimple_on_selected_autoprocessing_file(instruction) + + elif instruction == "Run PHENIX.LIGAND_PIPELINE on selected MTZ files": + self.run_dimple_on_selected_autoprocessing_file(instruction) + + elif instruction == "Remove selected DIMPLE files": + self.remove_selected_dimple_files(instruction) + + elif instruction == "Remove selected PIPEDREAM files": + self.remove_selected_dimple_files(instruction) + + elif instruction == "Remove selected PHENIX.LIGAND_PIPELINE files": + self.remove_selected_dimple_files(instruction) + + elif instruction == "Set DIMPLE output": + self.set_results_from_selected_pipeline(instruction) + + elif instruction == "Set PIPEDREAM output": + self.set_results_from_selected_pipeline(instruction) + + elif instruction == "Set PHENIX.LIGAND_PIPELINE output": + self.set_results_from_selected_pipeline(instruction) + + elif instruction == "Create CIF/PDB/PNG file of SELECTED compounds": + self.create_cif_pdb_png_files("SELECTED") + + elif instruction == "Merge ligand CIF file with selected compounds": + self.merge_cif_files("merge") + + elif instruction == "Restore original CIF file of selected compounds": + self.merge_cif_files("restore") + + elif instruction == "Fit ligands into maps after initial refinement": + self.fit_ligands_into_dimple_maps() + + elif instruction == "pandda.analyse": + self.run_pandda_analyse("production_run") + + elif instruction == "pandda.analyse (PanDDA2)": + self.run_pandda_analyse("production_run_pandda_two") + + elif instruction == "pre-run for ground state model": + self.run_pandda_analyse("pre_run") + + elif instruction == "pandda.inspect": + self.run_pandda_inspect() + + elif instruction == "run pandda.inspect at home": + self.run_pandda_inspect_at_home() + + elif instruction == "Export NEW PANDDA models": + update_datasource_only = False + which_models = "new" + self.run_pandda_export(update_datasource_only, which_models) + + elif instruction == "Export ALL PANDDA models": + update_datasource_only = False + which_models = "all" + self.run_pandda_export(update_datasource_only, which_models) + + elif instruction == "Export SELECTED PANDDA models": + update_datasource_only = False + which_models = "selected" + self.run_pandda_export(update_datasource_only, which_models) + + elif instruction == "refine ALL bound-state models with BUSTER": + self.run_refine_bound_state_with_buster("all") + + elif instruction == "refine NEW bound-state models with BUSTER": + self.run_refine_bound_state_with_buster("new") + + elif ( + instruction == "refine ALL bound-state models with BUSTER (no sanity check)" + ): + self.run_refine_bound_state_with_buster("allnocheck") + + elif ( + instruction == "refine NEW bound-state models with BUSTER (no sanity check)" + ): + self.run_refine_bound_state_with_buster("newnocheck") + + elif instruction == "cluster datasets": + self.cluster_datasets_for_pandda() + + elif instruction == "Update datasource with results from pandda.inspect": + update_datasource_only = True + which_models = "all" + self.run_pandda_export(update_datasource_only, which_models) + + elif instruction == "Show HTML summary": + self.show_pandda_html_summary() + + elif instruction == "Event Map -> SF": + self.convert_event_maps_to_SF() + + elif instruction == "apo -> mmcif": + self.convert_apo_to_mmcif() + + elif instruction == "check modelled ligands": + self.compare_modelled_ligands_and_panddaTable() + + elif ( + instruction.startswith("Open COOT") + or instruction == "Build ground state model" + ): + if not self.coot_running: + self.update_log.insert("starting coot...") + if instruction == "Open COOT": + interface = "new" + elif instruction == "Open COOT - REFMAC refinement -": + interface = "new" + elif instruction == "Open COOT - test -": + interface = "test" + elif instruction == "Open COOT for old PanDDA": + interface = "panddaV1" + elif instruction == "Build ground state model": + interface = "reference" + elif instruction == "Open COOT - BUSTER refinement -": + interface = "buster" + elif instruction == "Open COOT - dimple_twin -": + interface = "dimple_twin" + else: + interface = "old" + self.work_thread = XChemThread.start_COOT(self.settings, interface) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + elif instruction == "Update Deposition Table": + self.update_deposition_table() + + def run_pandda_analyse(self, run): + pandda_params = { + "data_dir": str(self.pandda_input_data_dir_entry.text()), + "out_dir": str(self.pandda_output_data_dir_entry.text()), + "submit_mode": str( + self.pandda_submission_mode_selection_combobox.currentText() + ), + "nproc": str(self.pandda_nproc_entry.text()), + "min_build_datasets": str(self.pandda_min_build_dataset_entry.text()), + "pdb_style": str(self.pandda_pdb_style_entry.text()), + "mtz_style": str(self.pandda_mtz_style_entry.text()), + "sort_event": str(self.pandda_sort_event_combobox.currentText()), + "average_map": str(self.pandda_calc_map_combobox.currentText()), + "max_new_datasets": str(self.pandda_max_new_datasets_entry.text()), + "grid_spacing": str(self.pandda_grid_spacing_entry.text()), + "keyword_arguments": str(self.pandda_keyword_arguments_entry.text()), + "pandda_dir_structure": str(self.pandda_input_data_dir_entry.text()), + "perform_diffraction_data_scaling": str(self.wilson_checkbox.isChecked()), + "filter_pdb": str( + self.pandda_reference_file_selection_combobox.currentText() + ), + "reference_dir": self.reference_directory, + "appendix": "", + "N_datasets": len( + glob.glob(os.path.join(self.initial_model_directory, "*", "dimple.pdb")) + ), + "write_mean_map": "interesting", + "pandda_table": self.pandda_analyse_data_table, + } + + if run == "pre_run": + msgBox = QtGui.QMessageBox() + msgBoxLayout = msgBox.layout() + vbox = QtGui.QVBoxLayout() + vbox.addWidget( + QtGui.QLabel(XChemToolTips.pandda_pre_run(self.reference_directory)) + ) + hbox = QtGui.QHBoxLayout() + hbox.addWidget(QtGui.QLabel("appendix:")) + appendix = QtGui.QLineEdit() + appendix.setText("pre") + appendix.setFixedWidth(200) + hbox.addWidget(appendix) + vbox.addLayout(hbox) + + msgBoxLayout.addLayout(vbox, 0, 0) + msgBox.addButton(QtGui.QPushButton("Go"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("Cancel"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + if reply == 0: + pandda_params["appendix"] = str(appendix.text()) + pandda_params["max_new_datasets"] = "100" + pandda_params["N_datasets"] = 100 + pandda_params["write_mean_map"] = "all" + else: + return None + + self.update_log.insert("preparing pandda.analyse input script") + if run == "production_run_pandda_two": + self.work_thread = XChemPANDDA.run_pandda_two_analyse( + pandda_params, + self.xce_logfile, + os.path.join(self.database_directory, self.data_source_file), + self.external_software, + get_token(fetch_password_qt), + ) + else: + self.work_thread = XChemPANDDA.run_pandda_analyse( + pandda_params, + self.xce_logfile, + os.path.join(self.database_directory, self.data_source_file), + self.external_software, + get_token(fetch_password_qt), + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def cluster_datasets_for_pandda(self): + pandda_params = { + "out_dir": str(self.pandda_output_data_dir_entry.text()), + "pdb_style": str(self.pandda_pdb_style_entry.text()), + "mtz_style": str(self.pandda_mtz_style_entry.text()), + } + self.update_log.insert("starting giant.cluster_mtzs_and_pdbs") + self.work_thread = XChemPANDDA.giant_cluster_datasets( + self.initial_model_directory, + pandda_params, + self.xce_logfile, + os.path.join(self.database_directory, self.data_source_file), + self.run_pandda_analyse, + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def run_pandda_inspect(self): + self.settings["panddas_directory"] = str( + self.pandda_output_data_dir_entry.text() + ) + print("==> XCE: starting pandda.inspect") + self.work_thread = XChemThread.start_pandda_inspect( + self.settings, self.xce_logfile + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def run_pandda_inspect_at_home(self): + self.work_thread = XChemPANDDA.run_pandda_inspect_at_home( + self.panddas_directory, self.xce_logfile + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + + def convert_event_maps_to_SF(self): + self.update_log.insert( + "converting all event maps in {0!s} to mtz files".format( + self.initial_model_directory + ) + ) + self.work_thread = XChemPANDDA.find_event_map_for_ligand( + self.initial_model_directory, self.xce_logfile, self.external_software + ) + + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def convert_apo_to_mmcif(self): + self.work_thread = XChemPANDDA.convert_apo_structures_to_mmcif( + self.panddas_directory, self.xce_logfile + ) + + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def compare_modelled_ligands_and_panddaTable(self): + self.update_log.insert( + "checking agreement of ligands in refine.pdb and entries in panddaTable" + ) + self.work_thread = XChemPANDDA.check_number_of_modelled_ligands( + self.initial_model_directory, + self.xce_logfile, + os.path.join(self.database_directory, self.data_source_file), + ) + self.explorer_active = 1 + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, QtCore.SIGNAL("show_error_dict"), self.show_error_dict + ) + self.work_thread.start() + + def run_pandda_export(self, update_datasource_only, which_models): + pandda_params = { + "data_dir": str(self.pandda_input_data_dir_entry.text()), + "out_dir": str(self.pandda_output_data_dir_entry.text()), + "submit_mode": str( + self.pandda_submission_mode_selection_combobox.currentText() + ), + "nproc": str(self.pandda_nproc_entry.text()), + "min_build_datasets": str(self.pandda_min_build_dataset_entry.text()), + "pdb_style": str(self.pandda_pdb_style_entry.text()), + "mtz_style": str(self.pandda_mtz_style_entry.text()), + "sort_event": str(self.pandda_sort_event_combobox.currentText()), + "average_map": str(self.pandda_calc_map_combobox.currentText()), + "max_new_datasets": str(self.pandda_max_new_datasets_entry.text()), + "grid_spacing": str(self.pandda_grid_spacing_entry.text()), + "pandda_dir_structure": str(self.pandda_input_data_dir_entry.text()), + "perform_diffraction_data_scaling": str(self.wilson_checkbox.isChecked()), + "filter_pdb": str( + self.pandda_reference_file_selection_combobox.currentText() + ), + "reference_dir": self.reference_directory, + "appendix": "", + "N_datasets": len( + glob.glob(os.path.join(self.initial_model_directory, "*", "dimple.pdb")) + ), + "write_mean_map": "interesting", + "pandda_table": self.pandda_analyse_data_table, + } + + self.settings["panddas_directory"] = str( + self.pandda_output_data_dir_entry.text() + ) + if update_datasource_only: + self.update_log.insert( + "updating data source with results from pandda.inspect" + ) + else: + self.update_log.insert( + "exporting PANDDA models," + " updating data source and launching inital refinement for new models" + ) + + start_thread = False + if which_models == "all": + self.update_log.insert( + "exporting ALL models!" + " *** WARNING *** This may overwrite previous refinements!!!" + ) + msgBox = QtGui.QMessageBox() + msgBox.setText( + "*** WARNING ***\n" + "This will overwrite all your manual selections!\n" + "Do you want to continue?" + ) + msgBox.addButton(QtGui.QPushButton("Yes"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("No"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + if reply == 0: + if update_datasource_only: + self.update_log.insert("will update panddaTable in database only") + else: + self.update_log.insert("will export ALL models!") + start_thread = True + else: + start_thread = False + else: + self.update_log.insert("exporting new models only") + start_thread = True + + if start_thread: + self.work_thread = XChemPANDDA.run_pandda_export( + self.panddas_directory, + os.path.join(self.database_directory, self.data_source_file), + self.initial_model_directory, + self.xce_logfile, + which_models, + pandda_params, + get_token(fetch_password_qt), + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def run_refine_bound_state_with_buster(self, which_models): + start_thread = True + if start_thread: + self.work_thread = XChemPANDDA.export_and_refine_ligand_bound_models( + self.panddas_directory, + os.path.join(self.database_directory, self.data_source_file), + self.initial_model_directory, + self.xce_logfile, + which_models, + get_token(fetch_password_qt), + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.work_thread.start() + + def show_pandda_html_summary(self): + self.pandda_initial_html.load(QtCore.QUrl(self.pandda_initial_html_file)) + self.pandda_initial_html.show() + self.pandda_analyse_html.load(QtCore.QUrl(self.pandda_analyse_html_file)) + self.pandda_analyse_html.show() + self.add_map_html() + self.pandda_inspect_html.load(QtCore.QUrl(self.pandda_inspect_html_file)) + self.pandda_inspect_html.show() + + def create_cif_pdb_png_files(self, todo): + tmp = self.db.execute_statement( + "select CrystalName,CompoundCode,CompoundSmiles from mainTable where" + " CrystalName is not '' and CompoundSmiles is not '' and CompoundSmiles" + " is not NULL;" + ) + compound_list = [] + for item in tmp: + if str(item[1]) == "" or str(item[1]) == "NULL": + compoundID = "compound" + else: + compoundID = str(item[1]) + + if todo == "ALL": + compound_list.append([str(item[0]), compoundID, str(item[2])]) + elif todo == "NEW": + if not os.path.isfile( + os.path.join( + self.initial_model_directory, str(item[0]), compoundID + ".cif" + ) + ): + compound_list.append([str(item[0]), compoundID, str(item[2])]) + elif todo == "SELECTED": + if str(item[0]) in self.initial_model_dimple_dict: + if self.initial_model_dimple_dict[str(item[0])][0].isChecked(): + compound_list.append([str(item[0]), compoundID, str(item[2])]) + + if compound_list: + self.update_log.insert( + "trying to create cif and pdb files for " + + str(len(compound_list)) + + " compounds using ACEDRG..." + ) + self.explorer_active = 1 + self.work_thread = XChemThread.create_png_and_cif_of_compound( + self.external_software, + self.initial_model_directory, + compound_list, + self.database_directory, + self.data_source_file, + todo, + self.ccp4_scratch_directory, + self.xce_logfile, + self.max_queue_jobs, + self.restraints_program, + get_token(fetch_password_qt), + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.work_thread.start() + + def fit_ligands_into_dimple_maps(self): + tmp = self.db.execute_statement( + "select CrystalName,CompoundCode,CompoundSmiles from mainTable where" + " CrystalName is not '' and CompoundSmiles is not '' and CompoundSmiles" + " is not NULL;" + ) + compound_list = [] + for item in tmp: + if str(item[1]) == "" or str(item[1]) == "NULL": + compoundID = "compound" + else: + compoundID = str(item[1]) + + if str(item[0]) in self.initial_model_dimple_dict: + if self.initial_model_dimple_dict[str(item[0])][0].isChecked(): + compound_list.append([str(item[0]), compoundID, str(item[2])]) + + if compound_list: + self.update_log.insert( + "trying to auto-fitting into inital maps for " + + str(len(compound_list)) + + " compounds..." + ) + self.explorer_active = 1 + self.work_thread = XChemThread.fit_ligands( + self.external_software, + self.initial_model_directory, + compound_list, + self.database_directory, + self.data_source_file, + self.ccp4_scratch_directory, + self.xce_logfile, + self.max_queue_jobs, + get_token(fetch_password_qt), + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.work_thread.start() + + def merge_cif_files(self, todo): + start_thread = False + if todo == "merge": + self.update_log.insert( + "trying to merge %s with ligand restraint files in project directory" + % self.second_cif_file + ) + elif todo == "restore": + self.update_log.insert("restoring original CIF files") + start_thread = True + + if todo == "merge": + if os.path.isfile(str(self.second_cif_file)): + self.update_log.insert( + "checking compound code of second CIF file (%s)" + % self.second_cif_file + ) + self.update_log.insert("Note: LIG and DRG are not allowed!") + import iotbx.cif + + cif_model = iotbx.cif.reader(file_path=self.second_cif_file).model() + cif_block = cif_model["comp_list"] + ligID = cif_block["_chem_comp.id"] + self.update_log.insert( + "found the following compound codes in the supplied CIF file: %s" + % str(list(ligID)) + ) + if "LIG" in list(ligID) or "DRG" in list(ligID): + self.update_log.error( + "please change compound code to something other than LIG or DRG" + ) + start_thread = False + else: + start_thread = True + else: + self.update_log.error(XChemToolTips.second_cif_file_not_exists()) + start_thread = False + + if start_thread: + msgBox = QtGui.QMessageBox() + msgBox.setText(XChemToolTips.second_cif_file_info(self.second_cif_file)) + msgBox.addButton(QtGui.QPushButton("OK"), QtGui.QMessageBox.YesRole) + msgBox.addButton( + QtGui.QPushButton("Cancel"), QtGui.QMessageBox.RejectRole + ) + reply = msgBox.exec_() + if reply == 0: + start_thread = True + else: + start_thread = False + else: + self.status_bar.showMessage( + "Error. Please check terminal window for further information" + ) + + tmp = self.db.execute_statement( + "select CrystalName,CompoundCode from mainTable where CrystalName is not ''" + " and CompoundSmiles is not '' and CompoundSmiles is not NULL;" + ) + compound_list = [] + for item in tmp: + xtal = str(item[0]) + compoundID = str(item[1]) + if compoundID == "" or compoundID == "NULL": + self.update_log.warning( + "%s: no compound ID in database; skipping..." % xtal + ) + else: + if str(item[0]) in self.initial_model_dimple_dict: + if self.initial_model_dimple_dict[str(item[0])][0].isChecked(): + self.update_log.warning( + "%s: %s is flagged for merging" % (xtal, compoundID) + ) + compound_list.append([xtal, compoundID]) + + if compound_list == []: + self.update_log.error( + "Either no compound ID information in database or no sample selected!" + ) + start_thread = False + + if start_thread: + self.explorer_active = 1 + self.work_thread = XChemThread.merge_cif_files( + self.initial_model_directory, + self.xce_logfile, + self.second_cif_file, + compound_list, + todo, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_progress_bar"), + self.update_progress_bar, + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("update_status_bar(QString)"), + self.update_status_bar, + ) + self.connect( + self.work_thread, QtCore.SIGNAL("finished()"), self.thread_finished + ) + self.connect( + self.work_thread, + QtCore.SIGNAL("datasource_menu_reload_samples"), + self.datasource_menu_reload_samples, + ) + self.work_thread.start() + + def update_deposition_table(self): + # check if PanDDA models are ready for deposition + + depositChecks = XChemDeposit.update_deposition_table( + os.path.join(self.database_directory, self.data_source_file) + ) + + toDeposit, mismatch = depositChecks.PanDDA_models_to_deposit() + + if mismatch != {}: + self.update_log.insert( + "The following samples contain ligand that are not ready for" + " deposition:" + ) + for entry in mismatch: + self.update_log.insert( + entry[0] + + " -> site: " + + entry[1] + + " @ " + + entry[2] + + " => " + + entry[4] + ) + self.update_log.insert("You need to change this before you can continue!") + return None + + for xtal in toDeposit: + self.db.update_insert_depositTable(xtal, {}) + + def need_to_switch_main_tab(self, task_index): + msgBox = QtGui.QMessageBox() + msgBox.setText("Need to switch main tab before you can launch this job") + msgBox.addButton(QtGui.QPushButton("Yes"), QtGui.QMessageBox.YesRole) + msgBox.addButton(QtGui.QPushButton("No"), QtGui.QMessageBox.RejectRole) + reply = msgBox.exec_() + if reply == 0: + self.main_tab_widget.setCurrentIndex(task_index) + + def check_write_permissions_of_data_source(self): + write_enabled = True + if not os.access( + os.path.join(self.database_directory, self.data_source_file), os.W_OK + ): + QtGui.QMessageBox.warning( + self.window, + "Data Source Problem", + "\nData Source is Read-Only\n", + QtGui.QMessageBox.Cancel, + QtGui.QMessageBox.NoButton, + QtGui.QMessageBox.NoButton, + ) + write_enabled = False + return write_enabled + + def no_data_source_selected(self): + QtGui.QMessageBox.warning( + self.window, + "Data Source Problem", + ("Please set or create a data source file\n") + + ("Options:\n") + + ("1. Use an existing file:\n") + + ("- Settings -> Select Data Source File\n") + + ("2. Create a new file\n") + + ("- Data Source -> Create New Data\nSource (SQLite)"), + QtGui.QMessageBox.Cancel, + QtGui.QMessageBox.NoButton, + QtGui.QMessageBox.NoButton, + ) + + def update_progress_bar(self, progress): + self.progress_bar.setValue(progress) + + def update_status_bar(self, message): + self.status_bar.showMessage(message) + + def thread_finished(self): + self.explorer_active = 0 + self.update_progress_bar(0) + self.update_status_bar("idle") + + def show_error_dict(self, errorDict): + text = "" + for key in errorDict: + text += "{0!s}:\n".format(key) + for entry in errorDict[key]: + text += " - " + entry + "\n" + msgBox = QtGui.QMessageBox() + msgBox.setText(text) + msgBox.exec_() + + def create_widgets_for_autoprocessing_results_only(self, data_dict): + self.status_bar.showMessage( + "Building details table for data processing results" + ) + self.data_collection_dict = data_dict + + column_name = [ + "Program", + "Resolution\nOverall", + "Resolution\n[Mn = 2.0]", + "DataProcessing\nSpaceGroup", + "Mn\nHigh", + "Rmerge\nLow", + "Completeness\nOverall", + "DataProcessing\nUnitCell", + "DataProcessing\nRfree", + "DataProcessing\nScore", + ] + + # need to do this because db_dict keys are SQLite column names + diffraction_data_column_name = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ).translate_xce_column_list_to_sqlite(column_name) + + for xtal in sorted(self.data_collection_dict): + # column 2: data collection date + # this one should always be there; it may need updating in case another run + # appears first find latest run + tmp = [] + for entry in self.data_collection_dict[xtal]: + if entry[0] == "image": + tmp.append( + [entry[3], datetime.strptime(entry[3], "%Y-%m-%d %H:%M:%S")] + ) + + # first check if it does already exist + if xtal not in self.data_collection_column_three_dict: + # generate all the widgets which can later be appended and add them to + # the dictionary table with data processing results for each pipeline + data_collection_table = QtGui.QTableWidget() + selection_changed_by_user = False + self.data_collection_column_three_dict[xtal] = [ + data_collection_table, + selection_changed_by_user, + ] + else: + data_collection_table = self.data_collection_column_three_dict[xtal][0] + selection_changed_by_user = self.data_collection_column_three_dict[ + xtal + ][1] + + data_collection_table.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarAlwaysOff + ) + data_collection_table.setColumnCount(len(column_name)) + font = QtGui.QFont() + font.setPointSize(8) + data_collection_table.setFont(font) + data_collection_table.setHorizontalHeaderLabels(column_name) + data_collection_table.horizontalHeader().setFont(font) + data_collection_table.setSelectionBehavior( + QtGui.QAbstractItemView.SelectRows + ) + + ############################################################################ + # crystal images + # first check there are new images that are not displayed yet; i.e. they + # are not in the self.data_collection_image_dict + if xtal not in self.data_collection_image_dict: + # OK this is the first time + self.data_collection_image_dict[xtal] = [] + + # sort crystal images by timestamp + # a) get only image entries from self.data_collection_dict + tmp = [] + for entry in self.data_collection_dict[xtal]: + if entry[0] == "image": + tmp.append(entry) + + # b) sort by the previously assigned run number + for entry in sorted(tmp, key=lambda x: x[6]): + run_number = entry[6] + images_already_in_table = False + for image in self.data_collection_image_dict[xtal]: + if run_number == image[0]: + images_already_in_table = True + break + if not images_already_in_table: + # not if there is a run, but images are for whatever reason not + # present in self.data_collection_dict then use image not available + # from $XChemExplorer_DIR/image/IMAGE_NOT_AVAILABLE.png + self.data_collection_image_dict[xtal].append( + [entry[6], entry[1], entry[2], entry[3], entry[5]] + ) + + ############################################################################ + # initialize dataset_outcome_dict for xtal + if xtal not in self.dataset_outcome_dict: + self.dataset_outcome_dict[xtal] = [] + # dataset outcome buttons + + ############################################################################ + # table for data processing results + # check if results from particular pipeline are already in table + row_position = data_collection_table.rowCount() + if xtal not in self.data_collection_table_dict: + self.data_collection_table_dict[xtal] = [] + logfile_list = [] + for entry in self.data_collection_dict[xtal]: + if entry[0] == "logfile": + logfile_list.append(entry) + # sort by aimless_index and so make sure + for entry in sorted(logfile_list, key=lambda x: x[7]): + entry_already_in_table = False # that aimless_index == row + cell_text = QtGui.QTableWidgetItem() + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + db_dict = entry[6] + for logfile in self.data_collection_table_dict[xtal]: + if ( + entry[1] == logfile[1] + and entry[2] == logfile[2] + and entry[3] == logfile[3] + and entry[4] == logfile[4] + ): + entry_already_in_table = True + # might have to update Rfree column + for column, header in enumerate(diffraction_data_column_name): + if header == "DataProcessing\nRfree": + # entry[7]==aimless_index, i.e. row number + cell_text.setText(str(db_dict[header[1]])) + data_collection_table.setItem( + entry[7], column, cell_text + ) + break + break + if not entry_already_in_table: + data_collection_table.insertRow(row_position) + for column, header in enumerate(diffraction_data_column_name): + cell_text = QtGui.QTableWidgetItem() + try: + cell_text.setText(str(db_dict[header[1]])) + except KeyError: + # this may happen if not score exists + cell_text.setText("0") + data_collection_table.setItem(row_position, column, cell_text) + data_collection_table.setRowHeight(row_position, 20) + row_position += 1 + + self.data_collection_table_dict[xtal].append( + ["logfile", entry[1], entry[2], entry[3], entry[4]] + ) # 'logfile' is just added to have + # same index numbers between lists + data_collection_table.cellClicked.connect( + self.user_update_selected_autoproc_datasets_summary_table + ) + + # select best resolution file + set data collection outcome + # the assumption is that index in data_collection_dict and row number are + # identical + # the assumption for data collection outcome is that as long as a logfile + # is found, it's a success + for entry in self.data_collection_dict[xtal]: + if entry[0] == "logfile": + index = entry[7] + best_file = entry[8] + if best_file: + # we change the selection only if the user did not touch it, + # assuming that he/she knows best if not + # selection_changed_by_user: + data_collection_table.selectRow(index) + + self.populate_datasets_summary_table() + + def find_suitable_reference_file(self, db_dict): + reference_file = [] + dummy = ["...", "", "", "", 0, "0"] + reference_file.append([dummy, 999]) + for reference in self.reference_file_list: + # first we need one in the same pointgroup + if reference[5] == db_dict["DataProcessingPointGroup"]: + try: + difference = ( + math.fabs( + 1 + - ( + float(db_dict["DataProcessingUnitCellVolume"]) + / float(reference[4]) + ) + ) + * 100 + ) + reference_file.append([reference, difference]) + except ValueError: + continue + return reference_file + + def create_maps_table(self): + column_name = self.db.translate_xce_column_list_to_sqlite( + self.maps_table_columns + ) + + for xtal in sorted(self.xtal_db_dict): + new_xtal = False + db_dict = self.xtal_db_dict[xtal] + if str(db_dict["DataCollectionOutcome"]).lower().startswith("success"): + reference_file = self.find_suitable_reference_file(db_dict) + smallest_uc_difference = min(reference_file, key=lambda x: x[1]) + row = self.maps_table.rowCount() + if xtal not in self.initial_model_dimple_dict: + self.maps_table.insertRow(row) + current_row = row + new_xtal = True + else: + for table_row in range(row): + if self.maps_table.item(table_row, 0).text() == xtal: + current_row = table_row + break + for column, header in enumerate(column_name): + if header[0] == "Sample ID": + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(xtal)) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.maps_table.setItem(current_row, column, cell_text) + elif header[0] == "Select": + if new_xtal: + run_dimple = QtGui.QCheckBox() + run_dimple.toggle() + self.maps_table.setCellWidget( + current_row, column, run_dimple + ) + run_dimple.setChecked(False) + elif header[0] == "Reference\nSpaceGroup": + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(smallest_uc_difference[0][1])) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.maps_table.setItem(current_row, column, cell_text) + elif header[0] == "Difference\nUC Volume (%)": + cell_text = QtGui.QTableWidgetItem() + smallest_uc_difference = min(reference_file, key=lambda x: x[1]) + cell_text.setText( + str(round(float(smallest_uc_difference[1]), 1)) + ) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.maps_table.setItem(current_row, column, cell_text) + elif header[0] == "Reference File": + if new_xtal: + reference_file_selection_combobox = QtGui.QComboBox() + self.populate_reference_combobox( + reference_file_selection_combobox + ) + if ( + float(smallest_uc_difference[1]) + < self.allowed_unitcell_difference_percent + ): + index = reference_file_selection_combobox.findText( + str(smallest_uc_difference[0][0]), + QtCore.Qt.MatchFixedString, + ) + reference_file_selection_combobox.setCurrentIndex(index) + else: + reference_file_selection_combobox.setCurrentIndex(0) + self.maps_table.setCellWidget( + current_row, column, reference_file_selection_combobox + ) + else: + reference_file_selection_combobox = ( + self.initial_model_dimple_dict[xtal][1] + ) + self.populate_reference_combobox( + reference_file_selection_combobox + ) + if ( + float(smallest_uc_difference[1]) + < self.allowed_unitcell_difference_percent + ): + index = reference_file_selection_combobox.findText( + str(smallest_uc_difference[0][0]), + QtCore.Qt.MatchFixedString, + ) + reference_file_selection_combobox.setCurrentIndex(index) + else: + reference_file_selection_combobox.setCurrentIndex(0) + else: + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(db_dict[header[1]])) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + if header[0] == "Dimple\nStatus": + if str(db_dict[header[1]]) == "running": + cell_text.setBackground(QtGui.QColor(100, 230, 150)) + elif str(db_dict[header[1]]) == "pending": + cell_text.setBackground(QtGui.QColor(20, 100, 230)) + elif str(db_dict[header[1]]) == "started": + cell_text.setBackground(QtGui.QColor(230, 240, 110)) + elif str(db_dict[header[1]]) == "finished": + cell_text.setBackground(QtGui.QColor(255, 255, 255)) + if header[0] == "Compound\nStatus": + if str(db_dict[header[1]]) == "running": + cell_text.setBackground(QtGui.QColor(100, 230, 150)) + elif str(db_dict[header[1]]) == "pending": + cell_text.setBackground(QtGui.QColor(20, 100, 230)) + elif str(db_dict[header[1]]) == "started": + cell_text.setBackground(QtGui.QColor(230, 240, 110)) + elif str(db_dict[header[1]]) == "restraints generated": + cell_text.setBackground(QtGui.QColor(255, 255, 255)) + elif str(db_dict[header[1]]) == "restraints failed": + cell_text.setBackground(QtGui.QColor(255, 0, 0)) + elif str(db_dict[header[1]]) == "missing smiles": + cell_text.setBackground(QtGui.QColor(240, 150, 20)) + self.maps_table.setItem(current_row, column, cell_text) + if new_xtal: + self.initial_model_dimple_dict[xtal] = [ + run_dimple, + reference_file_selection_combobox, + ] + + def preferences_data_to_copy_combobox_changed(self, i): + text = str(self.preferences_data_to_copy_combobox.currentText()) + for item in self.preferences_data_to_copy: + if item[0] == text: + self.preferences["processed_data_to_copy"] = item[1] + break + + def preferences_selection_mechanism_combobox_changed(self, i): + text = str(self.preferences_selection_mechanism_combobox.currentText()) + self.preferences["dataset_selection_mechanism"] = text + self.update_log.insert("setting datasets selection mechanism to " + text) + + def preferences_restraints_generation_combobox_changed(self): + text = str(self.preferences_restraints_generation_combobox.currentText()) + self.restraints_program = text + self.update_log.insert( + "will use {0!s} for generation of ligand coordinates and restraints".format( + text + ) + ) + + def refinement_outcome_combobox_changed(self): + for xtal in self.refinement_table_dict: + if self.sender() == self.refinement_table_dict[xtal]: + db_dict = {} + db_dict["RefinementOutcome"] = str(self.sender().currentText()) + db_dict["RefinementOutcomePerson"] = getpass.getuser() + db_dict["RefinementOutcomeDate"] = datetime.strftime( + datetime.now(), "%Y-%m-%d_%H-%M-%S.%f" + )[:-4] + self.db.create_or_remove_missing_records_in_depositTable( + self.xce_logfile, xtal, "ligand_bound", db_dict + ) + + def get_reference_file_list(self, reference_root): + # check available reference files + reference_file_list = [] + dummy = ["...", "", "", "", 0, "0"] + reference_file_list.append(dummy) + if os.path.isfile( + os.path.join(self.reference_directory, reference_root + ".pdb") + ): + pdb_reference = parse().PDBheader( + os.path.join(self.reference_directory, reference_root + ".pdb") + ) + spg_reference = pdb_reference["SpaceGroup"] + unitcell_reference = pdb_reference["UnitCell"] + lattice_reference = pdb_reference["Lattice"] + unitcell_volume_reference = pdb_reference["UnitCellVolume"] + pointgroup_reference = pdb_reference["PointGroup"] + reference_file_list.append( + [ + reference_root, + spg_reference, + unitcell_reference, + lattice_reference, + unitcell_volume_reference, + pointgroup_reference, + ] + ) + else: + for files in glob.glob(self.reference_directory + "/*"): + if files.endswith(".pdb"): + reference_root = files[files.rfind("/") + 1 : files.rfind(".")] + + if os.path.isfile( + os.path.join(self.reference_directory, reference_root + ".pdb") + ): + pdb_reference = parse().PDBheader( + os.path.join( + self.reference_directory, reference_root + ".pdb" + ) + ) + spg_reference = pdb_reference["SpaceGroup"] + unitcell_reference = pdb_reference["UnitCell"] + lattice_reference = pdb_reference["Lattice"] + unitcell_volume_reference = pdb_reference["UnitCellVolume"] + pointgroup_reference = pdb_reference["PointGroup"] + reference_file_list.append( + [ + reference_root, + spg_reference, + unitcell_reference, + lattice_reference, + unitcell_volume_reference, + pointgroup_reference, + ] + ) + for n, file in enumerate(reference_file_list): + self.update_log.insert("reference file {0!s}: {1!s}".format(n, file)) + return reference_file_list + + def dataset_outcome_combobox_change_outcome(self, text): + outcome = str(text) + xtal = "" + for key in self.dataset_outcome_combobox_dict: + if self.dataset_outcome_combobox_dict[key] == self.sender(): + xtal = key + self.update_log.insert( + "user changed data collection outcome of {0!s} to {1!s}".format( + xtal, outcome + ) + ) + break + self.dataset_outcome_dict[xtal] = outcome + if xtal != "": + # need to also update if not yet done + self.update_log.insert( + "updating dataset outcome in datasource for {0!s}".format(xtal) + ) + update_dict = {"DataCollectionOutcome": outcome} + self.db.update_insert_data_source(xtal, update_dict) + + def set_run_dimple_flag(self, state): + if state == QtCore.Qt.Checked: + for key in self.initial_model_dimple_dict: + self.initial_model_dimple_dict[key][0].setChecked(True) + else: + for key in self.initial_model_dimple_dict: + self.initial_model_dimple_dict[key][0].setChecked(False) + + #################################################################################### + # + # + # + # => new data collection summary table + # > start + + def get_sample_list_from_table(self, table): + sampleList = [] + allRows = table.rowCount() + for row in range(0, allRows): + sample_id = str(table.item(row, 0).text()) + sampleList.append(sample_id) + return sorted(sampleList) + + def get_row_of_sample_in_table(self, table, xtal): + allRows = table.rowCount() + sampleRow = allRows + for n, row in enumerate(range(0, allRows)): + sample_id = str(table.item(row, 0).text()) + if sample_id == xtal: + sampleRow = n + break + return sampleRow + + def update_row_in_table(self, sample, row, db_dict, table, columns_to_show): + xtal = str(sample) + column_name = self.db.translate_xce_column_list_to_sqlite(columns_to_show) + + for column, header in enumerate(column_name): + if header[0] == "Sample ID": + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(xtal)) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + table.setItem(row, column, cell_text) + + elif header[0] == "DataCollection\nOutcome": + if xtal not in self.dataset_outcome_combobox_dict: + dataset_outcome_combobox = QtGui.QComboBox() + for outcomeItem in self.dataset_outcome: + dataset_outcome_combobox.addItem(outcomeItem) + dataset_outcome_combobox.activated[str].connect( + self.dataset_outcome_combobox_change_outcome + ) + self.dataset_outcome_combobox_dict[xtal] = dataset_outcome_combobox + table.setCellWidget(row, column, dataset_outcome_combobox) + index = self.dataset_outcome_combobox_dict[xtal].findText( + str(db_dict["DataCollectionOutcome"]), QtCore.Qt.MatchFixedString + ) + self.dataset_outcome_combobox_dict[xtal].setCurrentIndex(index) + + elif header[0].startswith("img"): + if os.path.isfile(db_dict[header[1]]): + pixmap = QtGui.QPixmap(db_dict[header[1]]) + else: + pixmap = QtGui.QPixmap( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "IMAGE_NOT_AVAILABLE.png", + ) + ) + image = QtGui.QLabel() + image.resize(128, 80) + image.setPixmap(pixmap.scaled(image.size(), QtCore.Qt.KeepAspectRatio)) + table.setCellWidget(row, column, image) + + elif header[0] == "Select": + checkbox = QtGui.QCheckBox() + checkbox.toggle() + if table == self.deposition_table_apo: + if xtal not in self.deposition_table_apo_dict: + self.deposition_table_apo_dict[xtal] = checkbox + if table == self.deposition_table_bound: + if xtal not in self.deposition_table_bound_dict: + self.deposition_table_bound_dict[xtal] = checkbox + table.setCellWidget(row, column, checkbox) + checkbox.setChecked(False) + + else: + cell_text = QtGui.QTableWidgetItem() + # in case data collection failed for whatever reason + try: + cell_text.setText(str(db_dict[header[1]])) + except KeyError: # older pkl files may not have all the columns + cell_text.setText("n/a") + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + table.setItem(row, column, cell_text) + print( + ( + "row: {0!s} column: {1!s} value: {2!s} header: {3!s}".format( + row, column, cell_text, header[0] + ) + ) + ) + print(("column_name {0!s}".format(column_name))) + + def populate_datasets_summary_table_NEW(self): + self.status_bar.showMessage( + "Building summary table for data processing results; be patient this may" + " take a while" + ) + + # get information about all samples collected during the current visit + visit, beamline = XChemMain.getVisitAndBeamline(self.beamline_directory) + if self.read_agamemnon.isChecked(): + visit = [] + for v in glob.glob( + os.path.join( + self.beamline_directory[: self.beamline_directory.rfind("-") + 1] + + "*" + ) + ): + visit.append(v[v.rfind("/") + 1 :]) + + self.update_log.insert( + "reading information about collected crystals from database..." + ) + collectedXtalsDict = self.db.xtals_collected_during_visit_as_dict(visit) + + # instead of using dictionaries, query table of which crystals are in table + samples_in_table = self.get_sample_list_from_table(self.datasets_summary_table) + for xtal in sorted(collectedXtalsDict): + if xtal not in samples_in_table: + row = self.datasets_summary_table.rowCount() + self.datasets_summary_table.insertRow(row) + else: + row = self.get_row_of_sample_in_table(self.datasets_summary_table, xtal) + db_dict = collectedXtalsDict[xtal] + self.update_row_in_table( + xtal, + row, + db_dict, + self.datasets_summary_table, + self.datasets_summary_table_columns, + ) + + self.datasets_summary_table.resizeRowsToContents() + self.datasets_summary_table.resizeColumnsToContents() + + self.status_bar.showMessage("updating Overview table") + + self.status_bar.showMessage("idle") + + def get_selected_row(self, table): + indexes = table.selectionModel().selectedRows() + for index in sorted(indexes): + selected_row = index.row() + return selected_row + + def show_results_from_all_pipelines(self): + selected_row = self.get_selected_row(self.datasets_summary_table) + xtal = self.datasets_summary_table.item(selected_row, 0).text() + # get details of currently selected autoprocessing result + selectedResultDict = self.db.get_db_dict_for_sample(xtal) + + dbList = self.db.all_autoprocessing_results_for_xtal_as_dict(xtal) + + self.make_data_collection_table() + # needs to be created here, otherwise the cellClicked function + dialog = QtGui.QDialog() + # will reference it before it exists + for db_dict in dbList: + if ( + str(db_dict["DataProcessingSpaceGroup"]).lower() == "null" + or str(db_dict["DataProcessingSpaceGroup"]).lower() == "none" + ): + continue + row = self.data_collection_table.rowCount() + self.data_collection_table.insertRow(row) + self.update_row_in_table( + xtal, + row, + db_dict, + self.data_collection_table, + self.data_collection_table_columns, + ) + if ( + selectedResultDict["DataCollectionVisit"] + == db_dict["DataCollectionVisit"] + and selectedResultDict["DataCollectionRun"] + == db_dict["DataCollectionRun"] + and selectedResultDict["DataProcessingProgram"] + == db_dict["DataProcessingProgram"] + and selectedResultDict["DataProcessingScore"] + == db_dict["DataProcessingScore"] + ): + self.current_row = row + self.data_collection_table.selectRow(row) + self.data_collection_table.cellClicked.connect( + lambda: self.select_different_autoprocessing_result(dialog) + ) + self.data_collection_table_popup(dialog) + + def make_data_collection_table(self): + # this creates a new table widget every time + # more elegant would be to delete or reset an existing widget... + self.data_collection_table = QtGui.QTableWidget() + self.data_collection_table.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarAlwaysOff + ) + self.data_collection_table.setColumnCount( + len(self.data_collection_table_columns) + ) + font = QtGui.QFont() + font.setPointSize(8) + self.data_collection_table.setFont(font) + self.data_collection_table.setHorizontalHeaderLabels( + self.data_collection_table_columns + ) + self.data_collection_table.horizontalHeader().setFont(font) + self.data_collection_table.setSelectionBehavior( + QtGui.QAbstractItemView.SelectRows + ) + self.data_collection_table.setMinimumWidth(1000) + self.data_collection_table.setMinimumHeight(500) + + def data_collection_table_popup(self, dialog): + dialog_layout = QtGui.QGridLayout(dialog) + dialog_layout.addWidget(self.data_collection_table) + dialog.exec_() + + def select_different_autoprocessing_result(self, dialog): + selected_row = self.get_selected_row(self.data_collection_table) + if selected_row != self.current_row: + xtal = self.data_collection_table.item(selected_row, 0).text() + visit = self.data_collection_table.item(selected_row, 1).text() + run = self.data_collection_table.item(selected_row, 2).text() + autoproc = self.data_collection_table.item(selected_row, 3).text() + score = self.data_collection_table.item(selected_row, 12).text() + for q in range(13): + try: + print( + ( + "--> {0!s}: {1!s}".format( + q, + self.data_collection_table.item(selected_row, q).text(), + ) + ) + ) + except AttributeError: + print(("--> {0!s}: None".format(q))) + dbDict = self.db.get_db_dict_for_visit_run_autoproc_score( + xtal, visit, run, autoproc, score + ) + dbDict["DataProcessingAutoAssigned"] = "False" + self.update_log.insert( + "%s: changing selected autoprocessing result to %s %s %s" + % (xtal, visit, run, autoproc) + ) + # xtal is QString -> str(xtal) + XChemMain.linkAutoProcessingResult( + str(xtal), dbDict, self.initial_model_directory, self.xce_logfile + ) + self.update_log.insert("%s: updating row in Datasets table" % xtal) + self.db.update_data_source(str(xtal), dbDict) + self.update_log.insert( + "%s: getting updated information from DB mainTable" % xtal + ) + dbDict = self.db.get_db_dict_for_sample(xtal) + row = self.get_row_of_sample_in_table(self.datasets_summary_table, xtal) + self.update_row_in_table( + xtal, + row, + dbDict, + self.datasets_summary_table, + self.datasets_summary_table_columns, + ) + else: + print("nothing to change") + dialog.done(1) + + # < end + #################################################################################### + + def user_update_selected_autoproc_datasets_summary_table(self): + for key in self.data_collection_column_three_dict: + if self.data_collection_column_three_dict[key][0] == self.sender(): + self.update_log.insert("here: " + self.sender()) + self.update_log.insert( + "herere" + str(self.data_collection_column_three_dict) + ) + dbTmp = self.xtal_db_dict[key] + stage = dbTmp["RefinementOutcome"].split()[0] + print(("===>", key, stage)) + if int(stage) > 2: + msgBox = QtGui.QMessageBox() + msgBox.setText( + "*** WARNING ***\n" + "%s is currently %s\n" + "It will disappear from the Refinement table,\n" + "when you refresh it next time.\n" + "Do you want to continue?" % (key, dbTmp["RefinementOutcome"]) + ) + msgBox.addButton(QtGui.QPushButton("No"), QtGui.QMessageBox.YesRole) + msgBox.addButton( + QtGui.QPushButton("Yes"), QtGui.QMessageBox.RejectRole + ) + reply = msgBox.exec_() + if reply == 0: + self.update_log.insert( + "will not change data processing selection" + ) + # restore previous selection + for n, entry in enumerate(self.data_collection_dict[key]): + print(("==>", n)) + if entry[0] == "logfile": + if entry[8]: + print(("===> found:", n)) + self.data_collection_column_three_dict[key][ + 0 + ].selectRow(n) + break + + indexes = self.sender().selectionModel().selectedRows() + selected_processing_result = 1000000 + for index in sorted(indexes): + selected_processing_result = index.row() + # the user changed the selection, i.e. no automated selection will + # update it + self.update_log.insert("user changed selection") + self.data_collection_column_three_dict[key][1] = True + # need to also update if not yet done + user_already_changed_selection = False + for n, entry in enumerate(self.data_collection_dict[key]): + if entry[0] == "user_changed_selection": + user_already_changed_selection = True + if entry[0] == "logfile": + db_dict = entry[6] + db_dict["DataProcessingAutoAssigned"] = "False" + if entry[7] == selected_processing_result: + db_dict_current = entry[6] + program = db_dict["DataProcessingProgram"] + visit = db_dict["DataCollectionVisit"] + run = db_dict["DataCollectionRun"] + self.update_log.insert( + "user changed data processing files for {0!s}" + " to visit={1!s}, run={2!s}, program={3!s}".format( + key, visit, run, program + ) + ) + entry[8] = True + else: + entry[8] = False + + entry[6] = db_dict + self.data_collection_dict[key][n] = entry + if not user_already_changed_selection: + self.data_collection_dict[key].append(["user_changed_selection"]) + XChemMain.change_links_to_selected_data_collection_outcome( + key, + self.data_collection_dict, + self.data_collection_column_three_dict, + self.dataset_outcome_dict, + self.initial_model_directory, + os.path.join(self.database_directory, self.data_source_file), + self.xce_logfile, + ) + + # update 'Datasets' table + column_name = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ).translate_xce_column_list_to_sqlite( + self.datasets_summary_table_columns + ) + rows_in_table = self.datasets_summary_table.rowCount() + for row in range(rows_in_table): + if self.datasets_summary_table.item(row, 0).text() == key: + for column, header in enumerate(column_name): + if header[0] == "Sample ID": + continue + elif header[0] == "DataCollection\nOutcome": + continue + elif header[0].startswith("img"): + continue + elif header[0].startswith("Show"): + continue + else: + cell_text = QtGui.QTableWidgetItem() + try: + cell_text.setText(str(db_dict_current[header[1]])) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.datasets_summary_table.setItem( + row, column, cell_text + ) + except KeyError: + pass + + def populate_and_update_datasource_table(self): + self.overview_datasource_table.setColumnCount( + len(self.overview_datasource_table_columns) + ) + + # first get a list of all the samples that are already in the table and which + # will be updated + samples_in_table = [] + current_row = self.overview_datasource_table.rowCount() + for row in range(current_row): + sampleID = str( + self.overview_datasource_table.item(row, 0).text() + ) # this must be the case + samples_in_table.append(sampleID) + + columns_to_show = self.get_columns_to_show( + self.overview_datasource_table_columns + ) + sample_id_column = self.get_columns_to_show(["Sample ID"]) + + for row in self.data: + if ( + str(row[sample_id_column[0]]).lower() == "none" + or str(row[sample_id_column[0]]).replace(" ", "") == "" + ): + # do not show rows where sampleID is null + continue + else: + if not str(row[sample_id_column[0]]) in samples_in_table: + # insert row, this is a new sample + x = self.overview_datasource_table.rowCount() + self.overview_datasource_table.insertRow(x) + else: + # find row of this sample in data_source_table + for present_rows in range( + self.overview_datasource_table.rowCount() + ): + if str(row[sample_id_column[0]]) == str( + self.overview_datasource_table.item(present_rows, 0).text() + ): + x = present_rows + break + for y, item in enumerate(columns_to_show): + cell_text = QtGui.QTableWidgetItem() + if row[item] is None: + cell_text.setText("") + else: + cell_text.setText(str(row[item])) + # assumption is that column 0 is always sampleID + if self.overview_datasource_table_columns[y] == "Sample ID": + # and this field cannot be changed + cell_text.setFlags(QtCore.Qt.ItemIsEnabled) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.overview_datasource_table.setItem(x, y, cell_text) + self.overview_datasource_table.setHorizontalHeaderLabels( + self.overview_datasource_table_columns + ) + + def kill_other_pandda_options(self): + for i in range(0, self.pandda_analyse_data_table.rowCount()): + checkbox1 = self.pandda_analyse_data_table.cellWidget(i, 7) + checkbox2 = self.pandda_analyse_data_table.cellWidget(i, 8) + checkbox3 = self.pandda_analyse_data_table.cellWidget(i, 9) + if checkbox1.isChecked(): + checkbox2.setChecked(False) + checkbox3.setChecked(False) + if checkbox1.isChecked() and checkbox2.isChecked() or checkbox3.isChecked(): + checkbox1.setChecked(False) + if checkbox2.isChecked() or checkbox3.isChecked(): + checkbox1.setChecked(False) + + def populate_pandda_analyse_input_table(self): + column_name = self.db.translate_xce_column_list_to_sqlite( + self.pandda_table_columns + ) + print(column_name) + for xtal in sorted(self.xtal_db_dict): + new_xtal = False + db_dict = self.xtal_db_dict[xtal] + if os.path.isfile(db_dict["DimplePathToPDB"]): + row = self.pandda_analyse_data_table.rowCount() + if xtal not in self.pandda_analyse_input_table_dict: + self.pandda_analyse_data_table.insertRow(row) + current_row = row + new_xtal = True + else: + for table_row in range(row): + if ( + self.pandda_analyse_data_table.item(table_row, 0).text() + == xtal + ): + current_row = table_row + break + for column, header in enumerate(column_name): + if header[0] == "Exclude": + deselect_button = QtGui.QCheckBox() + deselect_button.stateChanged.connect( + self.kill_other_pandda_options + ) + self.pandda_analyse_data_table.setCellWidget( + current_row, column, deselect_button + ) + + elif header[0] == "Ignore": + deselect_button = QtGui.QCheckBox() + deselect_button.stateChanged.connect( + self.kill_other_pandda_options + ) + self.pandda_analyse_data_table.setCellWidget( + current_row, column, deselect_button + ) + + elif header[0] == "Export": + deselect_button = QtGui.QCheckBox() + deselect_button.stateChanged.connect( + self.kill_other_pandda_options + ) + self.pandda_analyse_data_table.setCellWidget( + current_row, column, deselect_button + ) + + elif header[0] == "Sample ID": + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(xtal)) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.pandda_analyse_data_table.setItem( + current_row, column, cell_text + ) + else: + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(db_dict[header[1]])) + if header[0] == "PanDDA\nStatus": + if str(db_dict[header[1]]) == "running": + cell_text.setBackground(QtGui.QColor(100, 230, 150)) + elif str(db_dict[header[1]]) == "pending": + cell_text.setBackground(QtGui.QColor(20, 100, 230)) + elif str(db_dict[header[1]]) == "started": + cell_text.setBackground(QtGui.QColor(230, 240, 110)) + elif str(db_dict[header[1]]) == "finished": + cell_text.setBackground(QtGui.QColor(255, 255, 255)) + elif "problem" in str(db_dict[header[1]]): + cell_text.setBackground(QtGui.QColor(255, 0, 0)) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.pandda_analyse_data_table.setItem( + current_row, column, cell_text + ) + if new_xtal: + self.pandda_analyse_input_table_dict[xtal] = [] + + def select_sample_for_pandda(self, option): + indexes = self.pandda_analyse_data_table.selectionModel().selectedRows() + if option == "deselect": + for index in sorted(indexes): + self.pandda_analyse_data_table.cellWidget(index.row(), 6).setChecked( + False + ) + self.pandda_analyse_data_table.cellWidget(index.row(), 7).setChecked( + False + ) + self.pandda_analyse_data_table.cellWidget(index.row(), 8).setChecked( + False + ) + else: + for index in sorted(indexes): + self.pandda_analyse_data_table.cellWidget(index.row(), 6).setChecked( + False + ) + self.pandda_analyse_data_table.cellWidget(index.row(), 7).setChecked( + False + ) + self.pandda_analyse_data_table.cellWidget(index.row(), 8).setChecked( + False + ) + if option == "ignore": + checkbox = self.pandda_analyse_data_table.cellWidget(index.row(), 6) + if option == "char": + checkbox = self.pandda_analyse_data_table.cellWidget(index.row(), 7) + if option == "zmap": + checkbox = self.pandda_analyse_data_table.cellWidget(index.row(), 8) + + checkbox.setChecked(True) + self.kill_other_pandda_options() + + def populate_and_update_refinement_table(self): + column_name = self.db.translate_xce_column_list_to_sqlite( + self.refinement_table_columns + ) + for xtal in sorted(self.xtal_db_dict): + new_xtal = False + db_dict = self.xtal_db_dict[xtal] + try: + stage = int(str(db_dict["RefinementOutcome"]).split()[0]) + refinementStage = db_dict["RefinementOutcome"] + except ValueError: + stage = 0 + except IndexError: + stage = 0 + + if stage >= 3 and stage < 7: + row = self.refinement_table.rowCount() + if xtal not in self.refinement_table_dict: + self.refinement_table.insertRow(row) + current_row = row + new_xtal = True + else: + for table_row in range(row): + if self.refinement_table.item(table_row, 0).text() == xtal: + current_row = table_row + break + for column, header in enumerate(column_name): + if header[0] == "Sample ID": + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(xtal)) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.refinement_table.setItem(current_row, column, cell_text) + + elif header[0] == "Refinement\nOutcome": + if new_xtal: + refinement_outcome_combobox = QtGui.QComboBox() + self.populate_refinement_outcome_combobox( + refinement_outcome_combobox + ) + self.refinement_table.setCellWidget( + current_row, column, refinement_outcome_combobox + ) + else: + refinement_outcome_combobox = self.refinement_table_dict[ + xtal + ] + index = refinement_outcome_combobox.findText( + refinementStage, QtCore.Qt.MatchFixedString + ) + refinement_outcome_combobox.setCurrentIndex(index) + refinement_outcome_combobox.currentIndexChanged.connect( + self.refinement_outcome_combobox_changed + ) + + elif header[0] == "buster-reports": + buster_report = db_dict["RefinementBusterReportHTML"] + ref_name = buster_report.split("/")[ + len(buster_report.split("/")) - 2 + ] + buster_report_link = QtGui.QLabel( + '
{1!s}'.format(buster_report, ref_name) + ) + buster_report_link.setOpenExternalLinks(True) + self.refinement_table.setCellWidget( + current_row, column, buster_report_link + ) + else: + cell_text = QtGui.QTableWidgetItem() + cell_text.setText(str(db_dict[header[1]])) + if header[0] == "Refinement\nStatus": + if str(db_dict[header[1]]) == "running": + cell_text.setBackground(QtGui.QColor(100, 230, 150)) + elif str(db_dict[header[1]]) == "pending": + cell_text.setBackground(QtGui.QColor(20, 100, 230)) + elif str(db_dict[header[1]]) == "started": + cell_text.setBackground(QtGui.QColor(230, 240, 110)) + elif str(db_dict[header[1]]) == "finished": + cell_text.setBackground(QtGui.QColor(255, 255, 255)) + elif "problem" in str(db_dict[header[1]]): + cell_text.setBackground(QtGui.QColor(255, 0, 0)) + cell_text.setTextAlignment( + QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter + ) + self.refinement_table.setItem(current_row, column, cell_text) + if new_xtal: + self.refinement_table_dict[xtal] = refinement_outcome_combobox + + self.refinement_table.resizeColumnsToContents() + self.refinement_table.resizeRowsToContents() + + def get_columns_to_show(self, column_list): + # maybe I coded some garbage before, but I need to find out which column name + # in the data source corresponds to the actually displayed column name in the + # table reason being that the unique column ID for DB may not be nice to look at + columns_to_show = [] + for column in column_list: + # first find out what the column name in the header is: + column_name = "" + for name in self.all_columns_in_data_source: + if column == name[1]: + column_name = name[0] + for n, all_column in enumerate(self.header): + if column_name == all_column: + columns_to_show.append(n) + break + return columns_to_show + + def quit_xce(self): + # save pkl file + if self.data_collection_dict != {}: + if os.path.isfile(self.datasets_summary_file): + self.update_log.insert("saving results to PKL file") + pickle.dump( + self.data_collection_dict, open(self.datasets_summary_file, "wb") + ) + self.update_log.insert("quitting XCE... bye,bye!") + QtGui.qApp.quit() diff --git a/xce/__init__.py b/xce/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/xce/__main__.py b/xce/__main__.py new file mode 100755 index 00000000..4154c5d5 --- /dev/null +++ b/xce/__main__.py @@ -0,0 +1,6 @@ +import sys + +from XChemExplorer import XChemExplorer + +if __name__ == "__main__": + XChemExplorer(sys.argv[1:]) diff --git a/xce/gui_scripts/__init__.py b/xce/gui_scripts/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/xce/gui_scripts/datasets_tab.py b/xce/gui_scripts/datasets_tab.py new file mode 100755 index 00000000..4c6d43c8 --- /dev/null +++ b/xce/gui_scripts/datasets_tab.py @@ -0,0 +1,76 @@ +from PyQt4 import QtCore, QtGui + +from xce.gui_scripts import layout_functions + + +class DatasetsTab: + def setup(self, xce_object): + ################################################################################ + # # + # DATASETS TAB # + # # + ################################################################################ + + # main body - things that are always displayed + # add a container to hold everythting and add to main tab layout + xce_object.datasets_data_collection_vbox = QtGui.QVBoxLayout() + + # add a horizontal box to hold option to autocheck for new data + xce_object.autocheck_hbox = QtGui.QHBoxLayout() + + # checkbox for autocollect + xce_object.check_for_new_data_collection = QtGui.QCheckBox( + "Check for new data collection every two minutes" + ) + layout_functions.add_checkbox( + xce_object, + xce_object.check_for_new_data_collection, + "xce_object.continously_check_for_new_data_collection", + ) + + # select target dropdown + select_target_label = QtGui.QLabel("Select Target: ") + select_target_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) + xce_object.target_selection_combobox = QtGui.QComboBox() + xce_object.populate_target_selection_combobox( + xce_object.target_selection_combobox + ) + xce_object.target_selection_combobox.activated[str].connect( + xce_object.target_selection_combobox_activated + ) + xce_object.target = str(xce_object.target_selection_combobox.currentText()) + + # array defining order of xce_objects to add + xce_object.autocheck_hbox_widgets = [ + xce_object.check_for_new_data_collection, + select_target_label, + xce_object.target_selection_combobox, + ] + + layout_functions.add_to_box( + xce_object.autocheck_hbox, xce_object.autocheck_hbox_widgets + ) # add xce_objects in order + + # add target dropdown to top bar + xce_object.datasets_data_collection_vbox.addLayout(xce_object.autocheck_hbox) + + # summary sub-tab + # table + xce_object.datasets_summary_table = QtGui.QTableWidget() + + xce_object.datasets_summary_table.resizeRowsToContents() + xce_object.datasets_summary_table.resizeColumnsToContents() + xce_object.datasets_summary_table.setSelectionBehavior( + QtGui.QAbstractItemView.SelectRows + ) + xce_object.datasets_summary_table.cellClicked.connect( + xce_object.show_results_from_all_pipelines + ) + + layout_functions.table_setup( + xce_object.datasets_summary_table, xce_object.datasets_summary_table_columns + ) + + xce_object.datasets_data_collection_vbox.addWidget( + xce_object.datasets_summary_table + ) # add subtab to main tab diff --git a/xce/gui_scripts/deposition_tab.py b/xce/gui_scripts/deposition_tab.py new file mode 100755 index 00000000..4e7cd2c7 --- /dev/null +++ b/xce/gui_scripts/deposition_tab.py @@ -0,0 +1,267 @@ +from PyQt4 import QtGui + +from xce.gui_scripts import layout_functions + +from xce.lib import XChemToolTips + + +class DepositionTab: + def setup(self, xce_object): + ################################################################################ + # # + # DEPOSITION TAB # + # # + ################################################################################ + xce_object.deposition_vbox = QtGui.QVBoxLayout() + + scroll = QtGui.QScrollArea() + xce_object.deposition_vbox.addWidget(scroll) + scrollContent = QtGui.QWidget(scroll) + scrollLayout = QtGui.QVBoxLayout(scrollContent) + scrollContent.setLayout(scrollLayout) + + # deposition page heading + deposition_page_heading = layout_functions.add_depo_heading( + "Group deposition of bound-state structures & ground-state model" + ) + deposition_page_heading.setStyleSheet("font: bold 40pt Arial") + + deposition_page_introduction = QtGui.QLabel( + XChemToolTips.deposition_introduction() + ) + deposition_page_introduction_link = QtGui.QLabel( + XChemToolTips.deposition_introduction_link() + ) + deposition_page_introduction_link.setOpenExternalLinks(True) + + # bound-state depostion + + deposition_bound_state_heading = layout_functions.add_depo_heading( + "Group deposition of bound-state structures" + ) + deposition_bound_state_heading.setStyleSheet("font: bold 20pt Arial") + + deposition_bound_state_prerequisites = layout_functions.add_depo_heading( + "Prerequisites" + ) + deposition_bound_state_prerequisites.setStyleSheet( + "font: italic bold 17pt Arial" + ) + + deposition_bound_state_prerequisites_text = layout_functions.add_depo_text( + XChemToolTips.deposition_bound_state_prerequisites() + ) + + deposition_bound_state_preparation = layout_functions.add_depo_heading( + "Procedure" + ) + deposition_bound_state_preparation.setStyleSheet( + "font: italic bold 17pt Arial " + ) + + deposition_bound_state_preparation_step_one_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_bound_state_preparation_step_one_text() + ) + ) + + xce_object.deposition_bounnd_state_preparation_ignore_event_map = ( + QtGui.QCheckBox( + XChemToolTips.deposition_bounnd_state_preparation_ignore_event_map() + ) + ) + + prepare_mmcif_button = QtGui.QPushButton("prepare mmcif") + prepare_mmcif_button.clicked.connect( + xce_object.prepare_models_for_deposition_ligand_bound + ) + prepare_mmcif_button.setMaximumWidth(200) + + deposition_bound_state_preparation_step_two_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_bound_state_preparation_step_two_text() + ) + ) + + copy_mmcif_button = QtGui.QPushButton("copy mmcif") + copy_mmcif_button.clicked.connect( + xce_object.prepare_for_group_deposition_upload_ligand_bound + ) + copy_mmcif_button.setMaximumWidth(200) + + pdb_group_deposition_instruction_one = layout_functions.add_depo_text( + XChemToolTips.pdb_group_deposition_instruction_one() + ) + + pdb_group_deposition_link = QtGui.QLabel( + XChemToolTips.pdb_group_deposition_link() + ) + pdb_group_deposition_link.setOpenExternalLinks(True) + + pdb_group_deposition_link_two = QtGui.QLabel( + XChemToolTips.pdb_group_deposition_link() + ) + pdb_group_deposition_link_two.setOpenExternalLinks(True) + + pdb_group_deposition_instruction_two = layout_functions.add_depo_text( + XChemToolTips.pdb_group_deposition_instruction_two() + ) + pdb_group_deposition_instruction_two_two = layout_functions.add_depo_text( + XChemToolTips.pdb_group_deposition_instruction_two() + ) + + # ground-state depostion + + deposition_ground_state_heading = layout_functions.add_depo_heading( + "Group deposition of ground-state model" + ) + deposition_ground_state_heading.setStyleSheet("font: bold 20pt Arial") + + deposition_ground_state_preparation_step_one_text = ( + layout_functions.add_depo_text( + XChemToolTips.notification_about_changes_to_apo_deposition() + ) + ) + + deposition_ground_state_prerequisites = layout_functions.add_depo_heading( + "Prerequisites" + ) + deposition_ground_state_prerequisites.setStyleSheet( + "font: italic bold 17pt Arial" + ) + + deposition_ground_state_prerequisites_text = layout_functions.add_depo_text( + XChemToolTips.deposition_ground_state_prerequisites() + ) + + deposition_ground_state_preparation = layout_functions.add_depo_heading( + "Procedure" + ) + deposition_ground_state_preparation.setStyleSheet( + "font: italic bold 17pt Arial " + ) + + deposition_ground_state_preparation_step_three_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_ground_state_preparation_step_three_text() + ) + ) + xce_object.ground_state_pandda_directory_label = QtGui.QLabel( + xce_object.panddas_directory + ) + xce_object.ground_state_pandda_directory_label.setStyleSheet("color: blue") + + deposition_ground_state_preparation_step_four_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_ground_state_preparation_step_four_text() + ) + ) + + add_ground_state_db_button = QtGui.QPushButton("Add to database") + add_ground_state_db_button.clicked.connect(xce_object.add_ground_state_db) + add_ground_state_db_button.setMaximumWidth(200) + + deposition_ground_state_preparation_step_five_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_ground_state_preparation_step_five_text() + ) + ) + + deposition_ground_state_preparation_step_six_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_ground_state_preparation_step_six_text() + ) + ) + + prepare_ground_state_mmcif_button = QtGui.QPushButton("Prepare mmcif") + prepare_ground_state_mmcif_button.clicked.connect( + xce_object.prepare_ground_state_mmcif + ) + prepare_ground_state_mmcif_button.setMaximumWidth(200) + + deposition_ground_state_preparation_step_seven_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_ground_state_preparation_step_seven_text() + ) + ) + + copy_apo_mmcif_button = QtGui.QPushButton("copy mmcif") + copy_apo_mmcif_button.clicked.connect( + xce_object.prepare_for_group_deposition_upload_ground_state + ) + copy_apo_mmcif_button.setMaximumWidth(200) + + deposition_ground_state_preparation_step_eight_text = ( + layout_functions.add_depo_text( + XChemToolTips.deposition_ground_state_preparation_step_eight_text() + ) + ) + + # after ligand_bound depostion + after_deposition_heading = layout_functions.add_depo_heading( + "After deposition of ligand-bound structures" + ) + after_deposition_heading.setStyleSheet("font: bold 20pt Arial") + + after_deposition_preparation = layout_functions.add_depo_heading("Procedure") + after_deposition_preparation.setStyleSheet("font: italic bold 17pt Arial ") + after_deposition_preparation_text = layout_functions.add_depo_text( + XChemToolTips.after_deposition_step_one_text() + ) + + ############################################### + + deposition_widget_list = [ + deposition_page_heading, + QtGui.QLabel(" \n "), + deposition_page_introduction, + deposition_page_introduction_link, + QtGui.QLabel(" \n "), + deposition_bound_state_heading, + QtGui.QLabel(" \n "), + deposition_bound_state_prerequisites, + deposition_bound_state_prerequisites_text, + QtGui.QLabel(" \n "), + deposition_bound_state_preparation, + deposition_bound_state_preparation_step_one_text, + xce_object.deposition_bounnd_state_preparation_ignore_event_map, + prepare_mmcif_button, + deposition_bound_state_preparation_step_two_text, + copy_mmcif_button, + pdb_group_deposition_instruction_one, + pdb_group_deposition_link, + pdb_group_deposition_instruction_two_two, + QtGui.QLabel(" \n\n\n "), + after_deposition_heading, + QtGui.QLabel(" \n "), + after_deposition_preparation, + after_deposition_preparation_text, + QtGui.QLabel(" \n\n\n "), + deposition_ground_state_heading, + QtGui.QLabel(" \n "), + deposition_ground_state_preparation_step_one_text, + QtGui.QLabel(" \n "), + deposition_ground_state_prerequisites, + deposition_ground_state_prerequisites_text, + QtGui.QLabel(" \n "), + deposition_ground_state_preparation, + deposition_ground_state_preparation_step_three_text, + xce_object.ground_state_pandda_directory_label, + deposition_ground_state_preparation_step_four_text, + add_ground_state_db_button, + deposition_ground_state_preparation_step_five_text, + deposition_ground_state_preparation_step_six_text, + prepare_ground_state_mmcif_button, + deposition_ground_state_preparation_step_seven_text, + copy_apo_mmcif_button, + deposition_ground_state_preparation_step_eight_text, + pdb_group_deposition_link_two, + pdb_group_deposition_instruction_two, + QtGui.QLabel(" \n\n\n "), + ] + + layout_functions.add_to_box(scrollLayout, deposition_widget_list) + + # container settings + scrollLayout.addStretch(1) + scroll.setWidget(scrollContent) diff --git a/xce/gui_scripts/layout.py b/xce/gui_scripts/layout.py new file mode 100755 index 00000000..07f03986 --- /dev/null +++ b/xce/gui_scripts/layout.py @@ -0,0 +1,385 @@ +import os + +from PyQt4 import QtGui + +from xce.gui_scripts.datasets_tab import DatasetsTab +from xce.gui_scripts.deposition_tab import DepositionTab +from xce.gui_scripts.maps_tab import MapsTab +from xce.gui_scripts.overview_tab import OverviewTab +from xce.gui_scripts.pandda_tab import PanddaTab +from xce.gui_scripts.refinement_tab import RefinementTab +from xce.gui_scripts.settings_preferences import setup +from xce.gui_scripts.settings_tab import SettingsTab +from xce.gui_scripts import layout_functions + + +class LayoutObjects: + def initialise_menu_bar(self, xce_object): + ################################################################################ + # # + # MENU BAR - TOP OF GUI # + # # + ################################################################################ + + # initiate menu widget + menu_bar = QtGui.QMenuBar() + + # import menu bar dictionary + setup().top_menu_dict(xce_object) + + # create menu from menu dictionary + menu_bar = layout_functions.setup_menubar( + xce_object, menu_bar, xce_object.menu_dict + ) + + # END OF MENU BAR - CODE BELOW: stuff removed from apo structure stuff that + # appears might have a funky consequence - work out later. + return menu_bar + + # function containing setup for bottom boxes + def initialise_bottom_boxes(self, xce_object): + icons_directory = os.path.join((os.getenv("XChemExplorer_DIR")), "xce/icons") + + # import all buttons + setup().bottom_box_buttons(xce_object) + + # setup datasource button + update_from_datasource_button = layout_functions.setup_push_button( + xce_object, xce_object.datasource_button_dict + ) + + ################################################################################ + # # + # DATASETS BOX # + # # + ################################################################################ + + # setup the run button with push button function + xce_object.dataset_task_run_button = layout_functions.setup_push_button( + xce_object, xce_object.dataset_task_run_button_dict + ) + + # setup the task button with push button function + xce_object.dataset_task_status_button = layout_functions.setup_push_button( + xce_object, xce_object.dataset_task_status_button_dict + ) + + # array of both button xce_objects to apply to bottom box layout + dataset_buttons = [ + xce_object.dataset_task_run_button, + xce_object.dataset_task_status_button, + ] + + # label for the bottom box layout + dataset_label = str( + " Datasets" + ) + + # return the frame and combobox from the bottom box setup function + ( + frame_dataset_task, + xce_object.dataset_tasks_combobox, + ) = layout_functions.bottom_box_setup( + xce_object, + dataset_label, + xce_object.dataset_tasks, + "XChemToolTips." "dataset_task_tip()", + dataset_buttons, + "background: " "rgb(240, 255, 140);", + ) + + # define the combobox and buttons in dictionary key to determine behaviour + xce_object.workflow_widget_dict["Datasets"] = [ + xce_object.dataset_tasks_combobox, + xce_object.dataset_task_run_button, + xce_object.dataset_task_status_button, + ] + + ################################################################################ + # # + # MAPS & RESTRAINTS BOX # + # # + ################################################################################ + # settings for the run button + + # setup the run button with push button function + xce_object.map_cif_file_task_run_button = layout_functions.setup_push_button( + xce_object, xce_object.map_cif_file_task_run_button_dict + ) + + # setup the task button with push button function + xce_object.map_cif_file_task_status_button = layout_functions.setup_push_button( + xce_object, xce_object.map_cif_file_task_status_button_dict + ) + + # array of both button xce_objects to apply to bottom box layout + map_cif_file_buttons = [ + xce_object.map_cif_file_task_run_button, + xce_object.map_cif_file_task_status_button, + ] + + # label for the bottom box layout + map_cif_file_label = str( + " Maps & Restraints" + ) + + # return the frame and combobox from the bottom box setup function + ( + frame_map_cif_file_task, + xce_object.map_cif_file_tasks_combobox, + ) = layout_functions.bottom_box_setup( + xce_object, + map_cif_file_label, + xce_object.map_cif_file_tasks, + "XChemToolTips.map_cif_file_" "task_tip()", + map_cif_file_buttons, + "background: rgb(140, 255, " "150); ", + ) + + # define the combobox and buttons in dictionary key to determine behaviour + xce_object.workflow_widget_dict["Maps"] = [ + xce_object.map_cif_file_tasks_combobox, + xce_object.map_cif_file_task_run_button, + xce_object.map_cif_file_task_status_button, + ] + + ################################################################################ + # # + # HIT IDENTIFICATION BOX # + # # + ################################################################################ + # settings for the run button + + # setup the run button with push button function + xce_object.panddas_file_task_run_button = layout_functions.setup_push_button( + xce_object, xce_object.panddas_file_task_run_button_dict + ) + + # setup the task button with push button function + xce_object.panddas_file_task_status_button = layout_functions.setup_push_button( + xce_object, xce_object.panddas_file_task_status_button_dict + ) + + # array of both button xce_objects to apply to bottom box layout + panddas_file_buttons = [ + xce_object.panddas_file_task_run_button, + xce_object.panddas_file_task_status_button, + ] + + # label for the bottom box layout + panddas_file_label = str( + " Hit Identification" + ) + + # return the frame and combobox from the bottom box setup function + ( + frame_panddas_file_task, + xce_object.panddas_file_tasks_combobox, + ) = layout_functions.bottom_box_setup( + xce_object, + panddas_file_label, + xce_object.panddas_file_tasks, + "XChemToolTips.panddas_file_" "task_tip()", + panddas_file_buttons, + "background: rgb(140,200,255)" "; ", + ) + + # define the combobox and buttons in dictionary key to determine behaviour + xce_object.workflow_widget_dict["PANDDAs"] = [ + xce_object.panddas_file_tasks_combobox, + xce_object.panddas_file_task_run_button, + xce_object.panddas_file_task_status_button, + ] + + ################################################################################ + # # + # REFINEMENT BOX # + # # + ################################################################################ + # settings for the run button + + # setup the run button with push button function + xce_object.refine_file_task_run_button = layout_functions.setup_push_button( + xce_object, xce_object.refine_file_task_run_button_dict + ) + + # setup the task button with push button function + xce_object.refine_file_task_status_button = layout_functions.setup_push_button( + xce_object, xce_object.refine_file_task_status_button_dict + ) + + # array of both button xce_objects to apply to bottom box layout + refine_file_buttons = [ + xce_object.refine_file_task_run_button, + xce_object.refine_file_task_status_button, + ] + + # label for the bottom box layout + refine_file_label = str( + " Refinement" + ) + + # return the frame and combobox from the bottom box setup function + ( + frame_refine_file_task, + xce_object.refine_file_tasks_combobox, + ) = layout_functions.bottom_box_setup( + xce_object, + refine_file_label, + xce_object.refine_file_tasks, + "XChemToolTips.refine_file_task" "_tip()", + refine_file_buttons, + "background: rgb(245, 190, 255)" ";", + ) + + # define the combobox and buttons in dictionary key to determine behaviour + xce_object.workflow_widget_dict["Refinement"] = [ + xce_object.refine_file_tasks_combobox, + xce_object.refine_file_task_run_button, + xce_object.refine_file_task_status_button, + ] + + return ( + update_from_datasource_button, + frame_dataset_task, + frame_map_cif_file_task, + frame_panddas_file_task, + frame_refine_file_task, + ) + + def main_layout(self, xce_object): + # initialise menu bar + menu_bar = self.initialise_menu_bar(xce_object) + + # initialise bottom boxes + ( + update_from_datasource_button, + frame_dataset_task, + frame_map_cif_file_task, + frame_panddas_file_task, + frame_refine_file_task, + ) = self.initialise_bottom_boxes(xce_object) + + # Tab layout & content + # -------------------- + # + # Overview + # |- datasource - TABLE + # |- summary - GRAPH + # + # Datasets + # |- summary - TABLE + # + # Maps - TABLE + # + # PANDDAS + # |- pandda.analyse - TABLE + # |- Dataset Summary ------------------ + # |- Processing Output | HTML + # |- pandda.inspect | + # |- Statistical Map Summaries -------- + # + # Refinement - TABLE + # + # Deposition + # + # Settings + + # Setup tabs + OverviewTab().setup(xce_object) + DatasetsTab().setup(xce_object) + MapsTab().setup(xce_object) + PanddaTab().setup(xce_object) + RefinementTab().setup(xce_object) + DepositionTab().setup(xce_object) + SettingsTab().setup(xce_object) + + ################################################################################ + # # + # STATUS BAR # + # # + ################################################################################ + xce_object.status_bar = QtGui.QStatusBar() + xce_object.progress_bar = QtGui.QProgressBar() + xce_object.progress_bar.setMaximum(100) + xce_object.status_bar.setMaximumWidth(xce_object.screen.width()) + xce_object.progress_bar.setMaximumWidth(xce_object.screen.width()) + hbox_status = QtGui.QHBoxLayout() + hbox_status.addWidget(xce_object.status_bar) + hbox_status.addWidget(xce_object.progress_bar) + + vbox_main = QtGui.QVBoxLayout() + menu_bar.setMaximumWidth(xce_object.screen.width()) + vbox_main.addWidget(menu_bar) + xce_object.main_tab_widget.setMaximumSize( + xce_object.screen.width(), xce_object.screen.height() - 245 + ) + vbox_main.addWidget(xce_object.main_tab_widget) + + hboxTaskFrames = QtGui.QHBoxLayout() + + hboxTaskFrames.addWidget(update_from_datasource_button) + hboxTaskFrames.addWidget(frame_dataset_task) + hboxTaskFrames.addWidget(frame_map_cif_file_task) + hboxTaskFrames.addWidget(frame_panddas_file_task) + hboxTaskFrames.addWidget(frame_refine_file_task) + + vbox_main.addLayout(hboxTaskFrames) + + vbox_main.addLayout(hbox_status) + + xce_object.window.setLayout(vbox_main) + + xce_object.status_bar.showMessage("Ready") + xce_object.window.show() + + if xce_object.data_source_file != "": + write_enabled = xce_object.check_write_permissions_of_data_source() + if not write_enabled: + xce_object.data_source_set = False + + def workflow(self, xce_object): + ################################################################################ + # # + # ========================== WORKFLOW TASK CONTAINER ========================= # + # # + ################################################################################ + + # workflow task container - order of tabs as they appear for the main window + xce_object.workflow = [ + "Overview", # 0 + "Datasets", # 1 + "Maps", # 2 + "PANDDAs", # 3 + "Refinement", # 4 + "Deposition", # 6 + "Settings", + ] # 5 + + # dictionary with keys corresponding to each stage in the workflow + xce_object.workflow_dict = { + xce_object.workflow[0]: "Overview", + xce_object.workflow[1]: "Datasets", + xce_object.workflow[2]: "Maps", + xce_object.workflow[3]: "PANDDAs", + xce_object.workflow[4]: "Refinement", + xce_object.workflow[6]: "Settings", + xce_object.workflow[5]: "Deposition", + } + + xce_object.workflow_widget_dict = {} + + # tab widget + xce_object.main_tab_widget = QtGui.QTabWidget() + xce_object.tab_dict = {} + layout_functions.make_tab_dict( + xce_object.workflow, xce_object.main_tab_widget, xce_object.tab_dict + ) diff --git a/xce/gui_scripts/layout_functions.py b/xce/gui_scripts/layout_functions.py new file mode 100755 index 00000000..4fc1d634 --- /dev/null +++ b/xce/gui_scripts/layout_functions.py @@ -0,0 +1,262 @@ +from PyQt4 import QtCore, QtGui +import os +from xce.lib import XChemToolTips # noqa: F401 + + +def make_tab_dict(tab_list, tab_widget, tab_dict): + for page in tab_list: + tab = QtGui.QWidget() + vbox = QtGui.QVBoxLayout(tab) + tab_widget.addTab(tab, page) + tab_dict[page] = [tab, vbox] + + +def add_checkbox(xce_object, checkbox, function, checkopt=False): + checkbox.toggle() + checkbox.setChecked(checkopt) + eval(str("checkbox.stateChanged.connect(" + function + ")")) + + +def table_setup(table, table_columns, sortingopt=True): + table.setColumnCount(len(table_columns)) + table.setSortingEnabled(sortingopt) + table.setHorizontalHeaderLabels(table_columns) + table.resizeRowsToContents() + table.resizeColumnsToContents() + + +def pandda_html(xce_object): + if os.path.exists(str(xce_object.panddas_directory + "/interesting_datasets")): + print( + "WARNING: USING RESULTS FROM OLD PANDDA ANALYSE!" + " THIS IS NOT FULLY SUPPORTED IN XCE2" + ) + print( + "PLEASE CHANGE YOUR PANDDA DIRECTORY TO A NEW RUN," + " OR USE THE OLD VERSION OF XCE!" + ) + xce_object.pandda_initial_html_file = str( + xce_object.panddas_directory + "/results_summareis/pandda_initial.html" + ) + xce_object.pandda_analyse_html_file = str( + xce_object.panddas_directory + "/results_summaries/pandda_analyse.html" + ) + xce_object.pandda_initial_html_file = str( + xce_object.panddas_directory + + "/analyses/html_summaries/" + + "pandda_initial.html" + ) + xce_object.pandda_analyse_html_file = str( + xce_object.panddas_directory + + "/analyses/html_summaries/" + + "pandda_analyse.html" + ) + xce_object.pandda_inspect_html_file = str( + xce_object.panddas_directory + + "/analyses/html_summaries/" + + "pandda_inspect.html" + ) + + +# function for datasource, run and status button setup +def setup_push_button(xce_object, button_dict): + # use iterkeys to determine order of key by letter + for name in sorted(button_dict.keys()): + # add current item to menu bar + button = eval('QtGui.QPushButton("' + str(button_dict[name][0]) + '")') + # for each configuration item + for button_config in button_dict[name][1]: + eval(str("button.setToolTip(" + str(button_config[0]) + ")")) + eval(str('button.setStyleSheet("' + str(button_config[1] + '")'))) + if len(button_config[2]) > 1: + eval(str("button.setFont(" + str(button_config[2]) + ")")) + eval(str("button.clicked.connect(" + str(button_config[3]) + ")")) + + return button + + +# function to setup one of the bottom boxes +def bottom_box_setup( + xce_object, label, dropdown_options, dropdown_tooltip, buttons, colour +): + frame = QtGui.QFrame() + frame.setFrameShape(QtGui.QFrame.StyledPanel) + frame.setStyleSheet( + "QFrame { " + "border-radius: 1px; padding: 0px; margin: 0px;" + " background-color: rgb(255, 255, 255); }" + ) + + vbox = QtGui.QVBoxLayout() + label = QtGui.QLabel(label) + label.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter) + label.setStyleSheet( + str( + " QLabel { border: 1px solid rgb(184, 192, 210); border-radius: 1px;" + + str(colour) + + "padding: 3px; margin: 0px; font: bold 14pt}" + ) + ) + vbox.addWidget(label) + + hboxAction = QtGui.QHBoxLayout() + combobox = QtGui.QComboBox() + for task in dropdown_options: + combobox.addItem(task) + eval("combobox.setToolTip(" + str(dropdown_tooltip) + ")") + combobox.setStyleSheet(" QComboBox { padding: 1px; margin: 1px }") + hboxAction.addWidget(combobox) + + vboxButton = QtGui.QVBoxLayout() + for button in buttons: + vboxButton.addWidget(button) + hboxAction.addLayout(vboxButton) + vbox.addLayout(hboxAction) + vbox.setSpacing(0) + vbox.setMargin(0) + frame.setLayout(vbox) + frame.setMaximumWidth((xce_object.screen.width() - 20) / 5) + + return frame, combobox + + +# function to add items to top menu bar +def setup_menubar(xce_object, menu_bar, menu_items_dict): + # use iterkeys to determine order of key by letter + for config in sorted(menu_items_dict.keys()): + # add current item to menu bar + menu = eval('menu_bar.addMenu("' + str(menu_items_dict[config][0]) + '")') + # for each configuration item + for menu_item in menu_items_dict[config][1]: + # add the drop down option + action = eval( + str('QtGui.QAction("' + str(menu_item[0]) + '", xce_object.window)') + ) + # add a shortcut if defined + if len(menu_item[1]) > 1: + eval(str('action.setShortcut("' + str(menu_item[1]) + '")')) + # connect the relevant function and add as an action + try: + action.triggered.connect(menu_item[2]) + menu.addAction(action) + except Exception as exception: + print((menu_item[2])) + raise exception + + return menu_bar + + +def add_to_box(frame, widgets_list): + for widget in widgets_list: + frame.addWidget(widget) + + +def populate_combobox(combobox_list, combobox): + for item in combobox_list: + combobox.addItem(item) + + +def add_depo_heading(heading_text): + heading = QtGui.QLabel(str(heading_text)) + heading.setStyleSheet("font: bold 20pt Arial") + + return heading + + +def add_depo_text(text): + out_text = QtGui.QLabel(text) + out_text.setStyleSheet("font: 17pt Arial") + + return out_text + + +def settings_section_setup(vbox, label_text, directory, button_text, button_function): + vbox.addWidget(QtGui.QLabel(label_text)) + + hbox = QtGui.QHBoxLayout() + directory_label = QtGui.QLabel(directory) + hbox.addWidget(directory_label) + button = QtGui.QPushButton(button_text) + button.setMaximumWidth(500) + button.clicked.connect(button_function) + hbox.addWidget(button) + + vbox.addLayout(hbox) + vbox.addWidget(QtGui.QLabel(" ")) + vbox.addWidget(QtGui.QLabel(" ")) + + return directory_label + + +def add_widgets_layouts(xce_object): + tab_add_widget = [ + [ + xce_object.tab_dict[xce_object.workflow_dict["Overview"]][1], + xce_object.overview_tab_widget, + ], + [ + xce_object.overview_tab_dict["Data Source"][1], + xce_object.overview_datasource_table, + ], + [ + xce_object.overview_tab_dict["Summary"][1], + xce_object.overview_canvas, + ], + [ + xce_object.pandda_tab_dict["Dataset Summary"][1], + xce_object.pandda_initial_html, + ], + [ + xce_object.pandda_tab_dict["Processing Output"][1], + xce_object.pandda_analyse_html, + ], + [ + xce_object.pandda_tab_dict["pandda.inspect"][1], + xce_object.pandda_inspect_html, + ], + ] + + tab_add_layout = [ + [ + xce_object.tab_dict[xce_object.workflow_dict["Datasets"]][1], + xce_object.datasets_data_collection_vbox, + ], + [ + xce_object.tab_dict[xce_object.workflow_dict["Maps"]][1], + xce_object.maps_checkbutton_hbox, + ], + [ + xce_object.tab_dict[xce_object.workflow_dict["Maps"]][1], + xce_object.initial_model_vbox_for_table, + ], + [ + xce_object.pandda_tab_dict["Statistical Map Summaries"][1], + xce_object.pandda_map_layout, + ], + [ + xce_object.pandda_tab_dict["pandda.analyse"][1], + xce_object.pandda_analyse_hbox, + ], + [ + xce_object.tab_dict[xce_object.workflow_dict["PANDDAs"]][1], + xce_object.panddas_results_vbox, + ], + [ + xce_object.tab_dict[xce_object.workflow_dict["Refinement"]][1], + xce_object.summary_vbox_for_table, + ], + [ + xce_object.tab_dict[xce_object.workflow_dict["Deposition"]][1], + xce_object.deposition_vbox, + ], + [ + xce_object.tab_dict[xce_object.workflow_dict["Settings"]][1], + xce_object.settings_vbox, + ], + ] + + for item in tab_add_widget: + item[0].addWidget(item[1]) + + for item in tab_add_layout: + item[0].addLayout(item[1]) diff --git a/xce/gui_scripts/maps_tab.py b/xce/gui_scripts/maps_tab.py new file mode 100755 index 00000000..d31a8bfb --- /dev/null +++ b/xce/gui_scripts/maps_tab.py @@ -0,0 +1,77 @@ +from PyQt4 import QtCore, QtGui + +from xce.gui_scripts import layout_functions + + +class MapsTab: + def setup(self, xce_object): + ################################################################################ + # # + # MAPS TAB # + # # + ################################################################################ + # select box for dimple + xce_object.select_sample_for_dimple_box = QtGui.QCheckBox( + "(de-)select all samples for DIMPLE" + ) + layout_functions.add_checkbox( + xce_object, + xce_object.select_sample_for_dimple_box, + "xce_object.set_run_dimple_flag", + ) + + # set new reference button + set_new_reference_button = QtGui.QPushButton( + "Set New Reference (if applicable)" + ) + set_new_reference_button.clicked.connect( + xce_object.set_new_reference_if_applicable + ) + + # refresh button + refresh_reference_file_list_button = QtGui.QPushButton( + "Refresh reference file list" + ) + refresh_reference_file_list_button.clicked.connect( + xce_object.refresh_reference_file_list + ) + + # list and populate reference files + xce_object.reference_file_list = xce_object.get_reference_file_list(" ") + xce_object.reference_file_selection_combobox = QtGui.QComboBox() + xce_object.populate_reference_combobox( + xce_object.reference_file_selection_combobox + ) + + # setup hbox to hold everything and add widgets + xce_object.maps_checkbutton_hbox = QtGui.QHBoxLayout() + maps_checkbutton_widgets = [ + xce_object.select_sample_for_dimple_box, + set_new_reference_button, + refresh_reference_file_list_button, + xce_object.reference_file_selection_combobox, + ] + + layout_functions.add_to_box( + xce_object.maps_checkbutton_hbox, maps_checkbutton_widgets + ) + + # table setup + xce_object.maps_table = QtGui.QTableWidget() + layout_functions.table_setup( + xce_object.maps_table, xce_object.maps_table_columns + ) + + # box for table, add to box, add to tab + xce_object.initial_model_vbox_for_table = QtGui.QVBoxLayout() + xce_object.initial_model_vbox_for_table.addWidget(xce_object.maps_table) + + # create context menu... no idea where this lives again. + xce_object.popMenu_for_maps_table = QtGui.QMenu() + run_dimple = QtGui.QAction("mark selected for dimple run", xce_object.window) + run_dimple.triggered.connect(xce_object.select_sample_for_dimple) + xce_object.popMenu_for_maps_table.addAction(run_dimple) + xce_object.maps_table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) + xce_object.maps_table.customContextMenuRequested.connect( + xce_object.on_context_menu_initial_model + ) diff --git a/gui_scripts/overview_tab.py b/xce/gui_scripts/overview_tab.py similarity index 56% rename from gui_scripts/overview_tab.py rename to xce/gui_scripts/overview_tab.py index 10180a8f..13db583e 100755 --- a/gui_scripts/overview_tab.py +++ b/xce/gui_scripts/overview_tab.py @@ -1,31 +1,28 @@ -import sys, os -from PyQt4 import QtGui, QtCore, QtWebKit - -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) - -import layout - import matplotlib.pyplot as plt from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas +from PyQt4 import QtGui +from xce.gui_scripts import layout_functions -class OverviewTab(): - def __init__(self): - self.layout_funcs = layout.LayoutFuncs() +class OverviewTab: def setup(self, xce_object): - ################################################################################################################ - # # - # OVERVIEW TAB # - # # - ################################################################################################################ + ################################################################################ + # # + # OVERVIEW TAB # + # # + ################################################################################ # define subtab list, widget and dict - overview_tab_list = ['Data Source', 'Summary'] + overview_tab_list = ["Data Source", "Summary"] xce_object.overview_tab_widget = QtGui.QTabWidget() xce_object.overview_tab_dict = {} # make subtabs - self.layout_funcs.make_tab_dict(overview_tab_list, xce_object.overview_tab_widget, xce_object.overview_tab_dict) + layout_functions.make_tab_dict( + overview_tab_list, + xce_object.overview_tab_widget, + xce_object.overview_tab_dict, + ) # initiate the table in overview/datasource xce_object.overview_datasource_table = QtGui.QTableWidget() @@ -35,4 +32,4 @@ def setup(self, xce_object): # initiate the graph in overview/summary xce_object.overview_figure, xce_object.overview_axes = plt.subplots() xce_object.overview_canvas = FigureCanvas(xce_object.overview_figure) - xce_object.update_summary_plot() \ No newline at end of file + xce_object.update_summary_plot() diff --git a/gui_scripts/pandda_tab.py b/xce/gui_scripts/pandda_tab.py similarity index 51% rename from gui_scripts/pandda_tab.py rename to xce/gui_scripts/pandda_tab.py index a2cef139..71c20bef 100755 --- a/gui_scripts/pandda_tab.py +++ b/xce/gui_scripts/pandda_tab.py @@ -1,34 +1,33 @@ -import sys, os, multiprocessing -from PyQt4 import QtGui, QtCore, QtWebKit +import multiprocessing +import os -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'gui_scripts')) -sys.path.append(os.path.join(os.getenv('XChemExplorer_DIR'), 'lib')) +from PyQt4 import QtCore, QtGui, QtWebKit -import layout -import XChemPANDDA +from xce.gui_scripts import layout_functions -class PanddaTab(): - def __init__(self): - self.layout_funcs = layout.LayoutFuncs() - +class PanddaTab: def setup(self, xce_object): - ################################################################################################################ - # # - # PANDDA TAB # - # # - ################################################################################################################ + ################################################################################ + # # + # PANDDA TAB # + # # + ################################################################################ # list of subtabs in PanDDA tab - pandda_tab_list = ['pandda.analyse', - 'Dataset Summary', - 'Processing Output', - 'pandda.inspect', - 'Statistical Map Summaries'] + pandda_tab_list = [ + "pandda.analyse", + "Dataset Summary", + "Processing Output", + "pandda.inspect", + "Statistical Map Summaries", + ] # setup tab widget, set up tab dict, and make tab dict xce_object.pandda_tab_widget = QtGui.QTabWidget() xce_object.pandda_tab_dict = {} - self.layout_funcs.make_tab_dict(pandda_tab_list, xce_object.pandda_tab_widget, xce_object.pandda_tab_dict) + layout_functions.make_tab_dict( + pandda_tab_list, xce_object.pandda_tab_widget, xce_object.pandda_tab_dict + ) # pandda analyse subtab # setup a grid to hold everything @@ -38,21 +37,28 @@ def setup(self, xce_object): # table - left xce_object.pandda_analyse_data_table = QtGui.QTableWidget() - self.layout_funcs.table_setup(xce_object.pandda_analyse_data_table, xce_object.pandda_table_columns) + layout_functions.table_setup( + xce_object.pandda_analyse_data_table, xce_object.pandda_table_columns + ) # add table to grid frame_pandda = QtGui.QFrame() grid_pandda.addWidget(xce_object.pandda_analyse_data_table, 0, 0) # status of pandda job - under table - xce_object.pandda_status = 'UNKNOWN' + xce_object.pandda_status = "UNKNOWN" xce_object.pandda_status_label = QtGui.QLabel() # status options [filename, test to output, colour of text] - pandda_status_options = [['/pandda.done', 'Finished!', 'color: green'], - ['/pandda.running', 'Running...', 'color: orange'], - ['/pandda.errored', 'Error encountered... please check the log files for pandda!', - 'color: red']] + pandda_status_options = [ + ["/pandda.done", "Finished!", "color: green"], + ["/pandda.running", "Running...", "color: orange"], + [ + "/pandda.errored", + "Error encountered... please check the log files for pandda!", + "color: red", + ], + ] # enumerate text options and set text under table for option in pandda_status_options: @@ -60,8 +66,12 @@ def setup(self, xce_object): xce_object.pandda_status = option[1] xce_object.pandda_status_label.setStyleSheet(option[2]) - xce_object.pandda_status_label.setText(str('STATUS: ' + xce_object.pandda_status)) - xce_object.pandda_status_label.setFont(QtGui.QFont("Arial", 25, QtGui.QFont.Bold)) + xce_object.pandda_status_label.setText( + str("STATUS: " + xce_object.pandda_status) + ) + xce_object.pandda_status_label.setFont( + QtGui.QFont("Arial", 25, QtGui.QFont.Bold) + ) grid_pandda.addWidget(xce_object.pandda_status_label, 3, 0) header_font = QtGui.QFont() @@ -74,105 +84,140 @@ def setup(self, xce_object): # data directory section pandda_input_dir_hbox = QtGui.QHBoxLayout() - label = QtGui.QLabel('Input data directory:') + label = QtGui.QLabel("Input data directory:") label.setFont(header_font) xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_input_data_dir_entry = QtGui.QLineEdit() - xce_object.pandda_input_data_dir_entry.setText(os.path.join(xce_object.initial_model_directory, '*')) + xce_object.pandda_input_data_dir_entry.setText( + os.path.join(xce_object.initial_model_directory, "*") + ) pandda_input_dir_hbox.addWidget(xce_object.pandda_input_data_dir_entry) - xce_object.select_pandda_input_dir_button = QtGui.QPushButton("Select Input Template") - xce_object.select_pandda_input_dir_button.clicked.connect(xce_object.select_pandda_input_template) + xce_object.select_pandda_input_dir_button = QtGui.QPushButton( + "Select Input Template" + ) + xce_object.select_pandda_input_dir_button.clicked.connect( + xce_object.select_pandda_input_template + ) pandda_input_dir_hbox.addWidget(xce_object.select_pandda_input_dir_button) xce_object.pandda_analyse_input_params_vbox.addLayout(pandda_input_dir_hbox) # pdb style section pandda_pdb_style_hbox = QtGui.QHBoxLayout() - label = QtGui.QLabel('pdb style') + label = QtGui.QLabel("pdb style") pandda_pdb_style_hbox.addWidget(label) xce_object.pandda_pdb_style_entry = QtGui.QLineEdit() - xce_object.pandda_pdb_style_entry.setText('dimple.pdb') + xce_object.pandda_pdb_style_entry.setText("dimple.pdb") pandda_pdb_style_hbox.addWidget(xce_object.pandda_pdb_style_entry) xce_object.pandda_analyse_input_params_vbox.addLayout(pandda_pdb_style_hbox) # mtz style section pandda_mtz_style_hbox = QtGui.QHBoxLayout() - label = QtGui.QLabel('mtz style') + label = QtGui.QLabel("mtz style") pandda_mtz_style_hbox.addWidget(label) xce_object.pandda_mtz_style_entry = QtGui.QLineEdit() - xce_object.pandda_mtz_style_entry.setText('dimple.mtz') + xce_object.pandda_mtz_style_entry.setText("dimple.mtz") pandda_mtz_style_hbox.addWidget(xce_object.pandda_mtz_style_entry) xce_object.pandda_analyse_input_params_vbox.addLayout(pandda_mtz_style_hbox) - print(xce_object.initial_model_directory) - data_dir_string = xce_object.initial_model_directory.replace('/*', '') + print((xce_object.initial_model_directory)) + data_dir_string = xce_object.initial_model_directory.replace("/*", "") def copy_ligands(obj): - os.system(str( - 'find ' + data_dir_string + - '/*/compound -name "*.cif" | while read line; do echo ${line//"' + - data_dir_string + '"/"' + xce_object.panddas_directory + - '/processed_datasets/"}| while read line2; do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; ' - 'done; done;')) - - os.system(str( - 'find ' + data_dir_string + - '/*/compound -name "*.pdb" | while read line; do echo ${line//"' + - data_dir_string + '"/"' + xce_object.panddas_directory + - '/processed_datasets/"}| while read line2; do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; ' - 'done; done;')) - - print('==> XCE: Copied ligand restraints over') + os.system( + str( + "find " + + data_dir_string + + '/*/compound -name "*.cif" | while read line; do echo ${line//"' + + data_dir_string + + '"/"' + + xce_object.panddas_directory + + '/processed_datasets/"}| while read line2;+' + " do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; " + "done; done;" + ) + ) + + os.system( + str( + "find " + + data_dir_string + + '/*/compound -name "*.pdb" | while read line; do echo ${line//"' + + data_dir_string + + '"/"' + + xce_object.panddas_directory + + '/processed_datasets/"}| while read line2;' + + " do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; " + "done; done;" + ) + ) + + print("==> XCE: Copied ligand restraints over") # output directory section pandda_output_dir_hbox = QtGui.QHBoxLayout() - label = QtGui.QLabel('Output directory:') + label = QtGui.QLabel("Output directory:") label.setFont(header_font) xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_output_data_dir_entry = QtGui.QLineEdit() xce_object.pandda_output_data_dir_entry.setText(xce_object.panddas_directory) pandda_output_dir_hbox.addWidget(xce_object.pandda_output_data_dir_entry) - xce_object.select_pandda_output_dir_button = QtGui.QPushButton("Select PanDDA Directory") - xce_object.select_pandda_output_dir_button.clicked.connect(xce_object.settings_button_clicked) + xce_object.select_pandda_output_dir_button = QtGui.QPushButton( + "Select PanDDA Directory" + ) + xce_object.select_pandda_output_dir_button.clicked.connect( + xce_object.settings_button_clicked + ) pandda_output_dir_hbox.addWidget(xce_object.select_pandda_output_dir_button) xce_object.pandda_analyse_input_params_vbox.addLayout(pandda_output_dir_hbox) - pandda_add_ligands_button = QtGui.QPushButton('Copy Ligand restraints for PanDDA') + pandda_add_ligands_button = QtGui.QPushButton( + "Copy Ligand restraints for PanDDA" + ) pandda_add_ligands_button.clicked.connect(lambda: copy_ligands(xce_object)) xce_object.pandda_analyse_input_params_vbox.addWidget(pandda_add_ligands_button) # spacer to separate out sections - spacer = QtGui.QLabel(' ') + spacer = QtGui.QLabel(" ") xce_object.pandda_analyse_input_params_vbox.addWidget(spacer) - label = QtGui.QLabel('Submission parameters') + label = QtGui.QLabel("Submission parameters") label.setFont(header_font) xce_object.pandda_analyse_input_params_vbox.addWidget(label) # qstat or local machine - label = QtGui.QLabel('Submit via:') + label = QtGui.QLabel("Submit via:") xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_submission_mode_selection_combobox = QtGui.QComboBox() - if xce_object.external_software['qsub']: - xce_object.pandda_submission_mode_selection_combobox.addItem('qsub') - xce_object.pandda_submission_mode_selection_combobox.addItem('local machine') - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.pandda_submission_mode_selection_combobox) + xce_object.pandda_submission_mode_selection_combobox.addItem("slurm") + xce_object.pandda_submission_mode_selection_combobox.addItem("local machine") + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_submission_mode_selection_combobox + ) # number of processors section - label = QtGui.QLabel('Number of processors:') + label = QtGui.QLabel("Number of processors:") xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_nproc = multiprocessing.cpu_count() - 1 xce_object.pandda_nproc_entry = QtGui.QLineEdit() - xce_object.pandda_nproc_entry.setText(str(xce_object.pandda_nproc).replace(' ', '')) - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.pandda_nproc_entry) + xce_object.pandda_nproc_entry.setText( + str(xce_object.pandda_nproc).replace(" ", "") + ) + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_nproc_entry + ) xce_object.pandda_analyse_input_params_vbox.addWidget(spacer) params_hbox = QtGui.QHBoxLayout() - label = QtGui.QLabel('PanDDA parameters') + label = QtGui.QLabel("PanDDA parameters") label.setFont(header_font) params_hbox.addWidget(label) - url_html = "For docs: click here" + url_html = ( + '' + "For docs: click here" + "" + ) label = QtGui.QLabel() label.setText(url_html) label.setOpenExternalLinks(True) @@ -182,61 +227,95 @@ def copy_ligands(obj): xce_object.pandda_analyse_input_params_vbox.addLayout(params_hbox) # checkbox for wilson scaling - xce_object.wilson_checkbox = QtGui.QCheckBox('Wilson B-factor Scaling') - self.layout_funcs.add_checkbox(xce_object, xce_object.wilson_checkbox, 'xce_object.set_run_dimple_flag') - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.wilson_checkbox) + xce_object.wilson_checkbox = QtGui.QCheckBox("Wilson B-factor Scaling") + layout_functions.add_checkbox( + xce_object, xce_object.wilson_checkbox, "xce_object.set_run_dimple_flag" + ) + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.wilson_checkbox + ) # crystal form option - label = QtGui.QLabel('Use space group of reference file as filter:') + label = QtGui.QLabel("Use space group of reference file as filter:") xce_object.pandda_analyse_input_params_vbox.addWidget(label) # reference file combobox, label with spg display hbox = QtGui.QHBoxLayout() # xce_object.reference_file_list = xce_object.get_reference_file_list('') xce_object.pandda_reference_file_selection_combobox = QtGui.QComboBox() - xce_object.populate_reference_combobox(xce_object.pandda_reference_file_selection_combobox) - xce_object.pandda_reference_file_selection_combobox.activated[str].connect(xce_object.change_pandda_spg_label) + xce_object.populate_reference_combobox( + xce_object.pandda_reference_file_selection_combobox + ) + xce_object.pandda_reference_file_selection_combobox.activated[str].connect( + xce_object.change_pandda_spg_label + ) hbox.addWidget(xce_object.pandda_reference_file_selection_combobox) xce_object.pandda_reference_file_spg_label = QtGui.QLabel() hbox.addWidget(xce_object.pandda_reference_file_spg_label) xce_object.pandda_analyse_input_params_vbox.addLayout(hbox) # how to order events - label = QtGui.QLabel('Order events by:') + label = QtGui.QLabel("Order events by:") xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_sort_event_combobox = QtGui.QComboBox() - pandda_events = ['cluster_size', 'z_peak'] - self.layout_funcs.populate_combobox(pandda_events, xce_object.pandda_sort_event_combobox) - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.pandda_sort_event_combobox) + pandda_events = ["cluster_size", "z_peak"] + layout_functions.populate_combobox( + pandda_events, xce_object.pandda_sort_event_combobox + ) + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_sort_event_combobox + ) # how calculate mean map - label = QtGui.QLabel('Calculate average map by:') + label = QtGui.QLabel("Calculate average map by:") xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_calc_map_combobox = QtGui.QComboBox() - average_map = ['mean_map', 'median_map'] - self.layout_funcs.populate_combobox(average_map, xce_object.pandda_calc_map_combobox) - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.pandda_calc_map_combobox) + average_map = ["mean_map", "median_map"] + layout_functions.populate_combobox( + average_map, xce_object.pandda_calc_map_combobox + ) + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_calc_map_combobox + ) # minimum number of datasets - label = QtGui.QLabel('min_build_datasets') + label = QtGui.QLabel("min_build_datasets") xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_min_build_dataset_entry = QtGui.QLineEdit() - xce_object.pandda_min_build_dataset_entry.setText('40') - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.pandda_min_build_dataset_entry) + xce_object.pandda_min_build_dataset_entry.setText("40") + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_min_build_dataset_entry + ) # maximum number of datasets - label = QtGui.QLabel('max_new_datasets') + label = QtGui.QLabel("max_new_datasets") xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_max_new_datasets_entry = QtGui.QLineEdit() - xce_object.pandda_max_new_datasets_entry.setText('300') - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.pandda_max_new_datasets_entry) + xce_object.pandda_max_new_datasets_entry.setText("300") + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_max_new_datasets_entry + ) # grid spacing label = QtGui.QLabel( - 'grid_spacing (default=0.5)\nNote: higher values speed up calculations, but maps might be less pretty)') + "grid_spacing (default=0.5)\n" + "Note: higher values speed up calculations, but maps might be less pretty)" + ) xce_object.pandda_analyse_input_params_vbox.addWidget(label) xce_object.pandda_grid_spacing_entry = QtGui.QLineEdit() - xce_object.pandda_grid_spacing_entry.setText('0.5') - xce_object.pandda_analyse_input_params_vbox.addWidget(xce_object.pandda_grid_spacing_entry) + xce_object.pandda_grid_spacing_entry.setText("0.5") + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_grid_spacing_entry + ) + + # keyword arguments (pandda2) + label = QtGui.QLabel("keyword arguments (pandda2 only)") + xce_object.pandda_analyse_input_params_vbox.addWidget(label) + xce_object.pandda_keyword_arguments_entry = QtGui.QLineEdit() + xce_object.pandda_keyword_arguments_entry.setText("") + xce_object.pandda_analyse_input_params_vbox.addWidget( + xce_object.pandda_keyword_arguments_entry + ) + frame_right.setLayout(xce_object.pandda_analyse_input_params_vbox) grid_pandda.addWidget(frame_right, 0, 1, 5, 5) @@ -248,45 +327,72 @@ def copy_ligands(obj): # statistical map summaries vbox, add to vbox and add to layout xce_object.pandda_map_layout = QtGui.QVBoxLayout() - pandda_map_layout_widgets = [xce_object.pandda_map_list, xce_object.pandda_maps_html] - self.layout_funcs.add_to_box(xce_object.pandda_map_layout, pandda_map_layout_widgets) + pandda_map_layout_widgets = [ + xce_object.pandda_map_list, + xce_object.pandda_maps_html, + ] + layout_functions.add_to_box( + xce_object.pandda_map_layout, pandda_map_layout_widgets + ) xce_object.pandda_maps_html.show() xce_object.pandda_analyse_hbox = QtGui.QHBoxLayout() xce_object.pandda_analyse_hbox.addWidget(frame_pandda) - ## change to do select options + # change to do select options # create context menu... no idea where this lives again. xce_object.popMenu_for_pandda_table = QtGui.QMenu() ignore = QtGui.QAction("ignore selected", xce_object.window) - exclude_characterisation = QtGui.QAction("exclude selected from characterisation", xce_object.window) - exclude_zmap = QtGui.QAction("exclude selected from z-map analysis", xce_object.window) + exclude_characterisation = QtGui.QAction( + "exclude selected from characterisation", xce_object.window + ) + exclude_zmap = QtGui.QAction( + "exclude selected from z-map analysis", xce_object.window + ) deselect = QtGui.QAction("deselect highlighted", xce_object.window) - ignore.triggered.connect(lambda: xce_object.select_sample_for_pandda(option='ignore')) - exclude_characterisation.triggered.connect(lambda: xce_object.select_sample_for_pandda(option='char')) - exclude_zmap.triggered.connect(lambda: xce_object.select_sample_for_pandda(option='zmap')) - deselect.triggered.connect(lambda: xce_object.select_sample_for_pandda(option='deselect')) + ignore.triggered.connect( + lambda: xce_object.select_sample_for_pandda(option="ignore") + ) + exclude_characterisation.triggered.connect( + lambda: xce_object.select_sample_for_pandda(option="char") + ) + exclude_zmap.triggered.connect( + lambda: xce_object.select_sample_for_pandda(option="zmap") + ) + deselect.triggered.connect( + lambda: xce_object.select_sample_for_pandda(option="deselect") + ) xce_object.popMenu_for_pandda_table.addAction(ignore) xce_object.popMenu_for_pandda_table.addAction(exclude_characterisation) xce_object.popMenu_for_pandda_table.addAction(exclude_zmap) xce_object.popMenu_for_pandda_table.addAction(deselect) - xce_object.pandda_analyse_data_table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - xce_object.pandda_analyse_data_table.customContextMenuRequested.connect(xce_object.on_context_menu_pandda) + xce_object.pandda_analyse_data_table.setContextMenuPolicy( + QtCore.Qt.CustomContextMenu + ) + xce_object.pandda_analyse_data_table.customContextMenuRequested.connect( + xce_object.on_context_menu_pandda + ) # next three blocks display html documents created by pandda.analyse - self.layout_funcs.pandda_html(xce_object) + layout_functions.pandda_html(xce_object) xce_object.pandda_initial_html = QtWebKit.QWebView() - xce_object.pandda_initial_html.load(QtCore.QUrl(xce_object.pandda_initial_html_file)) + xce_object.pandda_initial_html.load( + QtCore.QUrl(xce_object.pandda_initial_html_file) + ) xce_object.pandda_initial_html.show() xce_object.pandda_analyse_html = QtWebKit.QWebView() - xce_object.pandda_analyse_html.load(QtCore.QUrl(xce_object.pandda_analyse_html_file)) + xce_object.pandda_analyse_html.load( + QtCore.QUrl(xce_object.pandda_analyse_html_file) + ) xce_object.pandda_analyse_html.show() xce_object.pandda_inspect_html = QtWebKit.QWebView() - xce_object.pandda_analyse_html.load(QtCore.QUrl(xce_object.pandda_inspect_html_file)) + xce_object.pandda_analyse_html.load( + QtCore.QUrl(xce_object.pandda_inspect_html_file) + ) xce_object.pandda_analyse_html.show() xce_object.panddas_results_vbox = QtGui.QVBoxLayout() diff --git a/xce/gui_scripts/refinement_tab.py b/xce/gui_scripts/refinement_tab.py new file mode 100755 index 00000000..780e56bc --- /dev/null +++ b/xce/gui_scripts/refinement_tab.py @@ -0,0 +1,20 @@ +from PyQt4 import QtGui + +from xce.gui_scripts import layout_functions + + +class RefinementTab: + def setup(self, xce_object): + ################################################################################ + # # + # REFINEMENT TAB # + # # + ################################################################################ + xce_object.summary_vbox_for_table = QtGui.QVBoxLayout() + + # table + xce_object.refinement_table = QtGui.QTableWidget() + layout_functions.table_setup( + xce_object.refinement_table, xce_object.refinement_table_columns + ) + xce_object.summary_vbox_for_table.addWidget(xce_object.refinement_table) diff --git a/xce/gui_scripts/settings_preferences.py b/xce/gui_scripts/settings_preferences.py new file mode 100755 index 00000000..05b4f1c3 --- /dev/null +++ b/xce/gui_scripts/settings_preferences.py @@ -0,0 +1,755 @@ +import os +import subprocess +import sys +from PyQt4 import QtCore +from xce.lib import XChemDB, XChemLog, XChemMain, XChemUtils + + +class setup: + def __init__(self): + pass + + def openFile(self, file): + if sys.platform == "linux2": + subprocess.call(["xdg-open", file]) + else: + os.startfile(file) + + def set_xce_logfile(self, xce_object): + XChemLog.startLog(xce_object.xce_logfile).create_logfile(xce_object.xce_version) + xce_object.update_log = XChemLog.updateLog(xce_object.xce_logfile) + + def settings(self, xce_object): + # set XCE version + xce_object.xce_version = "v2.0.1" + + # general settings + xce_object.allowed_unitcell_difference_percent = 12 + xce_object.acceptable_low_resolution_limit_for_data = 3.5 + xce_object.filename_root = "${samplename}" + xce_object.data_source_set = False + xce_object.max_queue_jobs = 100 + + # directory settings + + # set current directory and direct log to it + xce_object.current_directory = os.getcwd() + xce_object.xce_logfile = os.path.join(xce_object.current_directory, "xce.log") + + # if in the correct place, set the various directories + if xce_object.current_directory.startswith("/dls/labxchem"): + # if 'labxchem' in xce_object.current_directory: + if ( + len(xce_object.current_directory.split("/")) >= 9 + and xce_object.current_directory.split("/")[6] == "processing" + and xce_object.current_directory.split("/")[8] == "processing" + ): + xce_object.labxchem_directory = "/" + os.path.join( + *xce_object.current_directory.split("/")[1:8] + ) # need splat operator: * + xce_object.labxchem_directory_current = "/" + os.path.join( + *xce_object.current_directory.split("/")[1:9] + ) + # labxchem_directory_current is where they actually have write + # permission + else: + xce_object.labxchem_directory = "/" + os.path.join( + *xce_object.current_directory.split("/")[1:6] + ) # need splat operator: * + xce_object.labxchem_directory_current = "/" + os.path.join( + *xce_object.current_directory.split("/")[1:7] + ) # need splat operator: * + xce_object.beamline_directory = os.path.join( + xce_object.labxchem_directory, "processing", "beamline" + ) + if os.path.isdir( + os.path.join( + xce_object.labxchem_directory, + "processing", + "analysis", + "model_building", + ) + ): + xce_object.initial_model_directory = os.path.join( + xce_object.labxchem_directory, + "processing", + "analysis", + "model_building", + ) + else: + xce_object.initial_model_directory = os.path.join( + xce_object.labxchem_directory, + "processing", + "analysis", + "initial_model", + ) + xce_object.reference_directory = os.path.join( + xce_object.labxchem_directory, "processing", "reference" + ) + xce_object.database_directory = os.path.join( + xce_object.labxchem_directory, "processing", "database" + ) + xce_object.panddas_directory = os.path.join( + xce_object.labxchem_directory, "processing", "analysis", "panddas" + ) + + xce_object.datasets_summary_file = None + xce_object.data_source_file = "" + xce_object.html_export_directory = os.path.join( + xce_object.labxchem_directory, "processing", "html" + ) + xce_object.group_deposit_directory = os.path.join( + xce_object.labxchem_directory, "processing", "group_deposition" + ) + if os.path.isfile( + os.path.join( + xce_object.labxchem_directory, + "processing", + "database", + "soakDBDataFile.sqlite", + ) + ): + xce_object.data_source_file = "soakDBDataFile.sqlite" + xce_object.database_directory = os.path.join( + xce_object.labxchem_directory, "processing", "database" + ) + xce_object.data_source_set = True + xce_object.db = XChemDB.data_source( + os.path.join( + xce_object.database_directory, xce_object.data_source_file + ) + ) + xce_object.db.create_missing_columns() + + xce_object.ccp4_scratch_directory = os.path.join( + xce_object.labxchem_directory, "processing", "tmp" + ) + + directory_list = [ + xce_object.beamline_directory, + os.path.join(xce_object.labxchem_directory, "processing", "analysis"), + xce_object.initial_model_directory, + xce_object.panddas_directory, + xce_object.reference_directory, + xce_object.database_directory, + xce_object.ccp4_scratch_directory, + xce_object.html_export_directory, + xce_object.group_deposit_directory, + ] + + for directory in directory_list: + if not os.path.isdir(directory): + os.mkdir(directory) + + # otherwise, use the current working directory + else: + xce_object.labxchem_directory_current = xce_object.current_directory + xce_object.beamline_directory = xce_object.current_directory + xce_object.initial_model_directory = xce_object.current_directory + xce_object.reference_directory = xce_object.current_directory + xce_object.database_directory = xce_object.current_directory + xce_object.data_source_file = "" + xce_object.ccp4_scratch_directory = os.getenv("CCP4_SCR") + xce_object.panddas_directory = xce_object.current_directory + xce_object.datasets_summary_file = "" + xce_object.group_deposit_directory = xce_object.current_directory + + # deposition + + xce_object.deposit_dict = {} + + # internal lists and dictionaries + + xce_object.visit_list = [] + xce_object.target = "" + xce_object.dataset_outcome_combobox_dict = {} + xce_object.data_collection_dict = {} + xce_object.xtal_db_dict = {} + xce_object.pandda_analyse_input_table_dict = {} + # contains toggle button if dimple should be run + xce_object.initial_model_dimple_dict = {} + xce_object.reference_file_list = [] + xce_object.all_columns_in_data_source = XChemDB.data_source( + os.path.join(xce_object.database_directory, xce_object.data_source_file) + ).return_column_list() + + xce_object.dataset_outcome_dict = {} # contains the dataset outcome buttons + xce_object.data_collection_table_dict = {} # contains the dataset table + xce_object.data_collection_image_dict = {} + xce_object.data_collection_column_three_dict = {} + xce_object.refinement_table_dict = {} + xce_object.timer_to_check_for_new_data_collection = QtCore.QTimer() + + xce_object.agamemnon = False + ( + xce_object.target_list, + xce_object.visit_list, + ) = XChemMain.get_target_and_visit_list(xce_object.beamline_directory, False) + + # internal switches and flags + + xce_object.explorer_active = 0 + xce_object.coot_running = 0 + xce_object.gdaLogInstructions = [0, False] + + xce_object.dataset_outcome = [ + "success", + "Failed - centring failed", + "Failed - no diffraction", + "Failed - processing", + "Failed - loop empty", + "Failed - loop broken", + "Failed - low resolution", + "Failed - no X-rays", + "Failed - unknown", + ] + + xce_object.refinement_stage = [ + "0 - All Datasets", + "1 - Analysis Pending", + "2 - PANDDA model", + "3 - In Refinement", + "4 - CompChem ready", + "5 - Deposition ready", + "6 - Deposited", + "7 - Analysed & Rejected", + ] + + self.set_xce_logfile(xce_object) + + # external software packages + xce_object.update_log = XChemLog.updateLog(xce_object.xce_logfile) + xce_object.update_log.insert("new session started") + xce_object.diffraction_data_directory = xce_object.current_directory + xce_object.html_export_directory = os.getcwd() + xce_object.external_software = XChemUtils.external_software( + xce_object.xce_logfile + ).check() + + xce_object.second_cif_file = None + + restraints_program_candidates = ["acedrg", "phenix.elbow", "grade"] + + xce_object.restraints_program = "" + for restraints_program_candidate in restraints_program_candidates: + if restraints_program_candidate in xce_object.external_software.keys(): + xce_object.restraints_program = restraints_program_candidate + xce_object.update_log.insert( + "will use {0!s} for" + " generation of ligand coordinates and restraints".format( + restraints_program_candidate + ) + ) + break + if xce_object.restraints_program is None: + xce_object.update_log.warning( + "No program for generation of ligand coordinates and restraints" + " available!" + ) + + def preferences(self, xce_object): + # preferences + + xce_object.preferences_data_to_copy = [ + ["aimless logiles and merged mtz only", "mtz_log_only"], + ] + + xce_object.preferences_selection_mechanism = [ + "IsigI*Comp*UniqueRefl", + "highest_resolution", + "lowest_Rfree", + "dials - only", + "xia2 3dii - only", + "autoProc - only", + "autoProc_staraniso - only", + ] + + xce_object.allowed_unitcell_difference_percent = 12 + xce_object.acceptable_low_resolution_limit_for_data = 3.5 + xce_object.filename_root = "${samplename}" + xce_object.max_queue_jobs = 100 + xce_object.dimple_twin_mode = False + + xce_object.preferences = { + "processed_data_to_copy": "mtz_log_only", + "dataset_selection_mechanism": "IsigI*Comp*UniqueRefl", + "allowed_unitcell_difference_percent": 12, + "acceptable_low_resolution_limit_for_data": 3.5, + "acceptable_low_resolution_Rmerge": 0.1, + "filename_root": "${samplename}", + "max_queue_jobs": 100, + "dimple_twin_mode": False, + "initial_refinement_pipeline": "dimple", + } + + # settings + + xce_object.settings = { + "current_directory": xce_object.current_directory, + "beamline_directory": xce_object.beamline_directory, + "datasets_summary": xce_object.datasets_summary_file, + "initial_model_directory": xce_object.initial_model_directory, + "panddas_directory": xce_object.panddas_directory, + "reference_directory": xce_object.reference_directory, + "database_directory": xce_object.database_directory, + "data_source": os.path.join( + xce_object.database_directory, xce_object.data_source_file + ), + "ccp4_scratch": xce_object.ccp4_scratch_directory, + "unitcell_difference": xce_object.allowed_unitcell_difference_percent, + "too_low_resolution_data": ( + xce_object.acceptable_low_resolution_limit_for_data + ), + "filename_root": xce_object.filename_root, + "preferences": xce_object.preferences, + "xce_logfile": xce_object.xce_logfile, + "max_queue_jobs": xce_object.max_queue_jobs, + "diffraction_data_directory": xce_object.diffraction_data_directory, + "html_export_directory": xce_object.html_export_directory, + "group_deposit_directory": xce_object.group_deposit_directory, + "dimple_twin_mode": False, + "agamemnon": False, + } + + def tables(self, xce_object): + # Table column settings + + # functions that use tables.overview_datasource_table_columns: + # + # select_datasource_columns_to_display() + # - dropdown in datasource top menu (select columns to show) + # populate_data_source_table() + # - appears to be completely unused, so commented out + # populate_and_update_datasource_table() + # - used within select_datasource_columns_to_display and + # update_all_tables() + + xce_object.overview_datasource_table_columns = [ + "Sample ID", + "Compound ID", + "Smiles", + "Visit", + "Resolution\n[Mn = 1.5]", + "Refinement\nRfree", + "Data Collection\nDate", + "Puck", + "PuckPosition", + "Ligand\nConfidence", + ] + + # functions that use tables.datasets_summary_table_columns: + # + # populate_datasets_summary_table() + # - appears in create_widgets_for_autoprocessing_results_only() + # user_update_selected_autoproc_datasets_summary_table() + # - appears in create_widgets_for_autoprocessing_results_only() + + xce_object.datasets_summary_table_columns = [ + "Sample ID", + "Resolution\nHigh", + "DataProcessing\nSpaceGroup", + "DataProcessing\nRfree", + "SoakDB\nBarcode", + "GDA\nBarcode", + "Rmerge\nLow", + "auto-assigned", + "DataCollection\nOutcome", + "img1", + "img2", + "img3", + "img4", + ] + + # functions that use tables.data_collection_table_columns: + # + # show_results_from_all_pipelines() + # - appears in populate_datasets_summary_table() + + xce_object.data_collection_table_columns = [ + "Sample ID", + "Visit", + "Run", + "Program", + "Resolution\nOverall", + "Resolution\nHigh", + "DataProcessing\nSpaceGroup", + "Mn\nHigh", + "Rmerge\nLow", + "Completeness\nOverall", + "DataProcessing\nUnitCell", + "DataProcessing\nRfree", + "DataProcessing\nScore", + ] + + # functions that use tables.maps_table_columns: + # + # - appears in create_maps_table() + + xce_object.maps_table_columns = [ + "Sample ID", + "Select", + "Compound ID", + "Smiles", + "Resolution\nHigh", + "Dimple\nRcryst", + "Dimple\nRfree", + "DataProcessing\nSpaceGroup", + "Reference\nSpaceGroup", + "Difference\nUC Volume (%)", + "Reference File", + "DataProcessing\nUnitCell", + "Dimple\nStatus", + "Compound\nStatus", + "LastUpdated", + ] + + # functions that use tables.pandda_table_columns: + # + # populate_pandda_analyse_input_table() + # - appears in update_all_tables() + + xce_object.pandda_table_columns = [ + "Sample ID", + "Export\nSelected", + "Refinement\nSpace Group", + "Resolution\n[Mn = 1.5]", + "Dimple\nRcryst", + "Dimple\nRfree", + "Crystal Form\nName", + "Ignore\ncompletely", + "Exclude from\n characterisation\n(binds)", + "Exclude from\n z-map analysis\n(does not bind)", + ] + + # functions that use tables.refinement_table_columns: + # + # populate_and_update_refinement_table() + # - appears in update_all_tables + + xce_object.refinement_table_columns = [ + "Sample ID", + "Compound ID", + "Refinement\nSpace Group", + "Refinement\nResolution", + "Refinement\nRcryst", + "Refinement\nRfree", + "Refinement\nOutcome", + "buster-reports", + "Ligand CC", + "Refinement\nStatus", + ] + + def top_menu_dict(self, xce_object): + xce_object.menu_dict = { + "A: file": [ + "&File", + [ + ["Open Config File", "Ctrl+O", xce_object.open_config_file], + ["Save Config File", "Ctrl+S", xce_object.save_config_file], + ["Quit", "Ctrl+Q", xce_object.quit_xce], + ], + ], + "B: datasource": [ + "&Datasource", + [ + [ + "Reload Samples From Datasource", + "", + xce_object.datasource_menu_reload_samples, + ], + [ + "Save Samples to Datasource", + "", + xce_object.datasource_menu_save_samples, + ], + [ + "Import CSV file into Datasource", + "", + xce_object.datasource_menu_import_csv_file, + ], + [ + "Export CSV file from Datasource", + "", + xce_object.datasource_menu_export_csv_file, + ], + [ + "Update datasource from file system", + "", + xce_object.datasource_menu_update_datasource, + ], + [ + "Select columns to show", + "", + xce_object.select_datasource_columns_to_display, + ], + [ + "Create New Datasource (SQLite)", + "", + xce_object.create_new_data_source, + ], + ["Export CSV for wonka", "", xce_object.export_data_for_WONKA], + ], + ], + "C: preferences": [ + "&Preferences", + [["Edit preferences", "", xce_object.show_preferences]], + ], + "D: deposition": [ + "&Deposition", + [ + ["Edit information", "", xce_object.deposition_data], + ["Export to HTML", "", xce_object.export_to_html], + [ + "Export to HTML - CompChem", + "", + xce_object.export_to_html_CompChem, + ], + [ + "Export to HTML - deposition ready", + "", + xce_object.export_to_html_deposition_ready, + ], + ["Update DB with PDB codes", "", xce_object.enter_pdb_codes], + ["Check SMILES", "", xce_object.check_smiles_in_db_and_pdb], + ], + ], + "F: help": [ + "&Help", + [ + [ + "Open XCE manual", + "", + lambda: setup().openFile( + "/dls/science/groups/i04-1/software/" + "XCE_manual_2018-11-09.pdf" + ), + ], + [ + "Open XCE tutorial", + "", + lambda: setup().openFile( + "/dls/science/groups/i04-1/software/docs/XChemExplorer.pdf" + ), + ], + [ + "Troubleshooting", + "", + lambda: setup().openFile( + "/dls/science/groups/i04-1/software/xce_troubleshooting.pdf" + ), + ], + ], + ], + "G: labels": [ + "&Labels", + [["Edit label information", "", xce_object.add_label_information]], + ], + } + + def bottom_box_buttons(self, xce_object): + self.dropdown_items(xce_object) + + xce_object.datasource_button_dict = { + "datasource_button": [ + r"Update Tables\nFrom Datasource", + [ + [ + "XChemToolTips.update_from_datasource_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px; " + "background: rgb(197,197,197) }", + # stylesheet + "xce_object.headlineLabelfont", # font + "xce_object.datasource_menu_reload_samples", + ] + # action + ], + ] + } + + xce_object.dataset_task_run_button_dict = { + "dataset_run_button": [ + r"Run", + [ + [ + "XChemToolTips.dataset_task_run_button_tip()", # tooltip + # stylesheet + "QPushButton { padding: 1px; margin: 1px }", + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + xce_object.dataset_task_status_button_dict = { + "dataset_status_button": [ + r"Status", + [ + [ + "XChemToolTips.dataset_task_status_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px }", + # stylesheet + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + xce_object.map_cif_file_task_run_button_dict = { + "dataset_run_button": [ + r"Run", + [ + [ + "XChemToolTips.map_cif_file_task_run_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px }", + # stylesheet + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + xce_object.map_cif_file_task_status_button_dict = { + "dataset_status_button": [ + r"Status", + [ + [ + "XChemToolTips.map_cif_file_task_status_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px }", + # stylesheet + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + xce_object.panddas_file_task_run_button_dict = { + "dataset_run_button": [ + r"Run", + [ + [ + "XChemToolTips.panddas_file_task_run_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px }", + # stylesheet + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + xce_object.panddas_file_task_status_button_dict = { + "dataset_status_button": [ + r"Status", + [ + [ + "XChemToolTips.panddas_file_task_status_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px }", + # stylesheet + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + xce_object.refine_file_task_run_button_dict = { + "dataset_run_button": [ + r"Run", + [ + [ + "XChemToolTips.refine_file_task_run_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px }", + # stylesheet + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + xce_object.refine_file_task_status_button_dict = { + "dataset_status_button": [ + r"Status", + [ + [ + "XChemToolTips.refine_file_task_status_button_tip()", + # tooltip + "QPushButton { padding: 1px; margin: 1px }", + # stylesheet + "", # font + "xce_object.button_clicked", + ] # action + ], + ] + } + + def dropdown_items(self, xce_object): + xce_object.dataset_tasks = [ + "Get New Results from Autoprocessing", + "Rescore Datasets", + "Run xia2 on selected datasets", + "Run xia2 on selected datasets - overwrite", + ] + + xce_object.map_cif_file_tasks = [ + "Run DIMPLE on selected MTZ files", + "Remove selected DIMPLE files", + "Set DIMPLE output", + "------------------------------------------", + "Create CIF/PDB/PNG file of SELECTED compounds", + "Merge ligand CIF file with selected compounds", + "Restore original CIF file of selected compounds", + "Fit ligands into maps after initial refinement", + "------------------------------------------", + "Run PIPEDREAM on selected MTZ files", + "Remove selected PIPEDREAM files", + "Set PIPEDREAM output", + "------------------------------------------", + "Run PHENIX.LIGAND_PIPELINE on selected MTZ files", + "Remove selected PHENIX.LIGAND_PIPELINE files", + "Set PHENIX.LIGAND_PIPELINE output", + ] + + xce_object.panddas_file_tasks = [ + "pre-run for ground state model", + "Build ground state model", + "------------------------------------------", + "pandda.analyse", + "pandda.analyse (PanDDA2)", + "pandda.inspect", + "run pandda.inspect at home", + "------------------------------------------", + "Export NEW PANDDA models", + "Export ALL PANDDA models", + "Export SELECTED PANDDA models", + "------------------------------------------", + "refine ALL bound-state models with BUSTER", + "refine NEW bound-state models with BUSTER", + "------------------------------------------", + "refine ALL bound-state models with BUSTER (no sanity check)", + "refine NEW bound-state models with BUSTER (no sanity check)", + "------------------------------------------", + "Show HTML summary", + "cluster datasets", + "Event Map -> SF", + "apo -> mmcif", + "check modelled ligands", + ] + + xce_object.refine_file_tasks = [ + "Open COOT - REFMAC refinement -", + "Open COOT - BUSTER refinement -", + "Open COOT - dimple_twin -", + "", + ] diff --git a/xce/gui_scripts/settings_tab.py b/xce/gui_scripts/settings_tab.py new file mode 100755 index 00000000..634d800c --- /dev/null +++ b/xce/gui_scripts/settings_tab.py @@ -0,0 +1,149 @@ +import os + +from PyQt4 import QtGui + +from xce.gui_scripts import layout_functions + + +class SettingsTab: + def setup(self, xce_object): + ################################################################################ + # # + # SETTINGS TAB # + # # + ################################################################################ + xce_object.settings_container = QtGui.QWidget() + xce_object.buttons_etc = QtGui.QWidget() + xce_object.settings_vbox = QtGui.QVBoxLayout() + + xce_object.scroll = QtGui.QScrollArea(xce_object.settings_container) + xce_object.settings_vbox.addWidget(xce_object.scroll) + scrollContent_settings = QtGui.QWidget(xce_object.scroll) + + scrollLayout_settings = QtGui.QVBoxLayout(scrollContent_settings) + scrollContent_settings.setLayout(scrollLayout_settings) + + # Settings Tab + xce_object.data_collection_vbox_for_settings = QtGui.QVBoxLayout() + + xce_object.buttons_etc.setLayout(xce_object.data_collection_vbox_for_settings) + xce_object.scroll.setWidget(xce_object.buttons_etc) + + xce_object.initial_model_directory_label = ( + layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nProject Directory: - REQUIRED -", + xce_object.initial_model_directory, + "Select Project Directory", + xce_object.settings_button_clicked, + ) + ) + + xce_object.reference_directory_label = layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nReference Structure Directory: - OPTIONAL -", + xce_object.reference_directory, + "Select Reference Structure Directory", + xce_object.settings_button_clicked, + ) + + if xce_object.data_source_file != "": + xce_object.data_source_file_label_text = os.path.join( + xce_object.database_directory, xce_object.data_source_file + ) + xce_object.data_source_file_label = layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nData Source: - REQUIRED -", + xce_object.data_source_file_label_text, + "Select Data Source File", + xce_object.settings_button_clicked, + ) + else: + xce_object.data_source_file_label_text = "" + + xce_object.data_source_file_label = layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nData Source: - REQUIRED -", + xce_object.data_source_file_label_text, + "Select Data Source File", + xce_object.settings_button_clicked, + ) + + xce_object.data_collection_vbox_for_settings.addWidget( + QtGui.QLabel( + "\n\nData Collection Directory:" + " (e.g. /dls/i04-1/data/2017/lb18145-70) -" + ) + ) + + settings_beamline_frame = QtGui.QFrame() + settings_beamline_frame.setFrameShape(QtGui.QFrame.StyledPanel) + settings_beamline_vbox = QtGui.QVBoxLayout() + + settings_hbox_beamline_directory = QtGui.QHBoxLayout() + xce_object.beamline_directory_label = QtGui.QLabel( + xce_object.beamline_directory + ) + settings_hbox_beamline_directory.addWidget(xce_object.beamline_directory_label) + settings_button_beamline_directory = QtGui.QPushButton( + "Select Data Collection Directory" + ) + settings_button_beamline_directory.setMaximumWidth(500) + + settings_button_beamline_directory.clicked.connect( + xce_object.settings_button_clicked + ) + + settings_hbox_beamline_directory.addWidget(settings_button_beamline_directory) + settings_beamline_vbox.addLayout(settings_hbox_beamline_directory) + xce_object.read_agamemnon = QtGui.QCheckBox("Read Agamemnon data structure") + xce_object.read_agamemnon.setChecked(True) + settings_beamline_vbox.addWidget(xce_object.read_agamemnon) + + settings_beamline_frame.setLayout(settings_beamline_vbox) + xce_object.data_collection_vbox_for_settings.addWidget(settings_beamline_frame) + + xce_object.ccp4_scratch_directory_label = ( + layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nCCP4_SCR Directory: - OPTIONAL -", + xce_object.ccp4_scratch_directory, + "Select CCP4_SCR Directory", + xce_object.settings_button_clicked, + ) + ) + + xce_object.panddas_directory_label = layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nPANDDAs directory: - OPTIONAL -", + xce_object.panddas_directory, + "Select PanDDA Directory", + xce_object.settings_button_clicked, + ) + + xce_object.html_export_directory_label = ( + layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nHTML export directory: - OPTIONAL -", + xce_object.html_export_directory, + "Select HTML Export Directory", + xce_object.settings_button_clicked, + ) + ) + + xce_object.group_deposition_directory_label = ( + layout_functions.settings_section_setup( + xce_object.data_collection_vbox_for_settings, + "\n\nGroup deposition directory: - OPTIONAL -", + xce_object.group_deposit_directory, + "Select Group deposition Directory", + xce_object.settings_button_clicked, + ) + ) + + xce_object.data_collection_vbox_for_settings.setContentsMargins(30, 30, 30, 30) + + xce_object.buttons_etc.resize( + xce_object.buttons_etc.sizeHint().width() + 100, + xce_object.buttons_etc.sizeHint().height(), + ) diff --git a/gui_scripts/stylesheet.py b/xce/gui_scripts/stylesheet.py similarity index 87% rename from gui_scripts/stylesheet.py rename to xce/gui_scripts/stylesheet.py index 0f97bdf2..1934180f 100755 --- a/gui_scripts/stylesheet.py +++ b/xce/gui_scripts/stylesheet.py @@ -1,21 +1,24 @@ -from PyQt4 import QtGui import os +from PyQt4 import QtGui + + def set_stylesheet(xce_object): palette = QtGui.QPalette() palette.setColor(QtGui.QPalette.Background, QtGui.QColor("#ececec")) xce_object.setPalette(palette) - icons_directory = os.path.join((os.getenv('XChemExplorer_DIR')), 'icons') + icons_directory = os.path.join((os.getenv("XChemExplorer_DIR")), "xce/icons") - xce_object.setStyleSheet(""" + xce_object.setStyleSheet( + """ QApplication { padding: 0px; } QMenuBar { background-color: rgb(236, 236, 236); - } + } QMenuBar::item { background-color: rgb(236, 236, 236); } @@ -37,7 +40,9 @@ def set_stylesheet(xce_object): border: 1px solid rgb(184, 192, 210); } QComboBox::down-arrow { - image: url(""" + icons_directory + """/drop-down.png); + image: url(""" + + icons_directory + + """/drop-down.png); background-color: rgb(255, 255, 255); } QComboBox::drop-down { @@ -75,6 +80,7 @@ def set_stylesheet(xce_object): QScrollBar { background: rgb(236, 236, 236); } - """) + """ + ) - QtGui.qApp.setStyle('Cleanlooks') \ No newline at end of file + QtGui.qApp.setStyle("Cleanlooks") diff --git a/xce/helpers/__init__.py b/xce/helpers/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/xce/helpers/create_png_of_compound.py b/xce/helpers/create_png_of_compound.py new file mode 100755 index 00000000..448bcf6c --- /dev/null +++ b/xce/helpers/create_png_of_compound.py @@ -0,0 +1,17 @@ +import os +import sys + +from rdkit import Chem +from rdkit.Chem import AllChem, Draw + +if __name__ == "__main__": + smiles = sys.argv[1] + compoundID = sys.argv[2] + xtal = sys.argv[3] + inital_model_directory = sys.argv[4] + + mol = Chem.MolFromSmiles(smiles) + AllChem.Compute2DCoords(mol) + + os.chdir(os.path.join(inital_model_directory, xtal, "compound")) + Draw.MolToFile(mol, "{0!s}.png".format(compoundID.replace(" ", ""))) diff --git a/xce/helpers/find_best_fitting_ligand.py b/xce/helpers/find_best_fitting_ligand.py new file mode 100755 index 00000000..1346106d --- /dev/null +++ b/xce/helpers/find_best_fitting_ligand.py @@ -0,0 +1,119 @@ +import glob +import os +import sys + + +def parse_autofit_folder(sampleDir, compoundID): + filenames = ["best.pdb", "ligand_fit_1.pdb"] + pdbList = [] + for files in glob.glob( + os.path.join(sampleDir, "autofit_ligand", compoundID + "_*", "*") + ): + pdb = files[files.rfind("/") + 1 :] + if pdb in filenames: + pdbList.append(files) + return pdbList + + +def find_input_mtz(sampleDir): + possibleMTZ = [ + "refine.mtz", + "init.mtz", + "dimple.mtz", + ] + mtzin = None + for mtz in possibleMTZ: + if os.path.isfile(os.path.join(sampleDir, mtz)): + mtzin = os.path.join(sampleDir, mtz) + break + return mtzin + + +def calculate_cc(sampleDir, compoundID, db): + xtal = sampleDir[sampleDir.rfind("/") + 1 :] + pdbList = parse_autofit_folder(sampleDir, compoundID) + mtzin = find_input_mtz(sampleDir) + for pdb in pdbList: + autofitDir = pdb[: pdb.rfind("/")] + os.chdir(autofitDir) + os.system( + "phenix.get_cc_mtz_pdb %s %s > phenix.get_cc_mtz_pdb.log" % (pdb, mtzin) + ) + new_file_links(pdbList) + bestRun, bestCC = parse_cc_log(sampleDir, compoundID) + changeLinks(sampleDir, pdbList, bestRun, compoundID) + fitting_program = None + if "phenix" in bestRun: + fitting_program = "phenix.ligandfit" + elif "rhofit" in bestRun: + fitting_program = "rhofit" + db_dict = {} + db_dict["CompoundAutofitprogram"] = fitting_program + db_dict["CompoundAutofitCC"] = str(bestCC) + updateDB(db, db_dict, xtal) + + +def new_file_links(pdbList): + for pdb in pdbList: + autofitDir = pdb[: pdb.rfind("/")] + autofitRun = pdb.split("/")[len(pdb.split("/")) - 2] + pdbFile = pdb[pdb.rfind("/") + 1 :] + os.chdir(autofitDir) + if not os.path.isfile(autofitRun + ".pdb"): + os.system("ln -s %s %s.pdb" % (pdbFile, autofitRun)) + + +def changeLinks(sampleDir, pdbList, bestRun, compoundID): + os.chdir(sampleDir) + for pdb in pdbList: + autofitDir = pdb.split("/")[len(pdb.split("/")) - 2] + if autofitDir == bestRun: + if os.path.isfile(pdb.replace(sampleDir, ".")): + os.system("/bin/rm %s.pdb" % compoundID) + os.system("ln -s %s %s.pdb" % (pdb.replace(sampleDir, "."), compoundID)) + + +def parse_cc_log(sampleDir, compoundID): + ccDict = {} + ccList = [] + for ccLog in glob.glob( + os.path.join( + sampleDir, "autofit_ligand", compoundID + "_*", "phenix.get_cc_mtz_pdb.log" + ) + ): + autofitDir = ccLog.split("/")[len(ccLog.split("/")) - 2] + for line in open(ccLog): + if line.startswith("local CC:") and len(line.split()) > 2: + cc = line.split()[2] + ccList.append(float(cc)) + ccDict[autofitDir] = cc + break + bestRun = None + try: + bestCC = max(ccList) + for ccRun in ccDict: + print(ccRun, ccDict[ccRun], bestCC) + if str(ccDict[ccRun]) == str(bestCC): + bestRun = ccRun + break + except ValueError: + pass + return bestRun, bestCC + + +def updateDB(db, db_dict, xtal): + db.update_data_source(xtal, db_dict) + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import XChemDB + + compoundID = sys.argv[1] + sampleDir = sys.argv[2] + database = sys.argv[3] + db = XChemDB.data_source(database) + + calculate_cc(sampleDir, compoundID, db) diff --git a/xce/helpers/make_ligand_links_after_pandda.py b/xce/helpers/make_ligand_links_after_pandda.py new file mode 100755 index 00000000..dd748c56 --- /dev/null +++ b/xce/helpers/make_ligand_links_after_pandda.py @@ -0,0 +1,9 @@ +import sys + +# projectDir='/dls/labxchem/data/2017/lb13385-109/processing/analysis/initial_model_cov' +# panddaDir='/dls/labxchem/data/2017/lb13385-109/processing/analysis/panddas_cov' + + +if __name__ == "__main__": + projectDir = sys.argv[1] + panddaDir = sys.argv[2] diff --git a/xce/helpers/merge_ligand_cif_files.py b/xce/helpers/merge_ligand_cif_files.py new file mode 100755 index 00000000..d972c1eb --- /dev/null +++ b/xce/helpers/merge_ligand_cif_files.py @@ -0,0 +1,19 @@ +import glob +import os +import sys + + +def merge_cifs(cpdDir): + os.chdir(cpdDir) + out = "" + for cif in glob.glob("*.cif"): + for line in open(cif): + out += line + f = open("merged.cif", "w") + f.write(out) + f.close() + + +if __name__ == "__main__": + cpdDir = sys.argv[1] + merge_cifs(cpdDir) diff --git a/xce/helpers/phenix_find_TLS_groups.py b/xce/helpers/phenix_find_TLS_groups.py new file mode 100755 index 00000000..08e81852 --- /dev/null +++ b/xce/helpers/phenix_find_TLS_groups.py @@ -0,0 +1,83 @@ +#!/usr/local/python/python2.7.3/bin/python +import os +import sys + + +def FindTLSgroups(pdbFile): + print("\n==> XCE @ helpers: running phenix.find_tls_groups on new pdb file") + os.system( + "phenix.find_tls_groups {0!s} > phenix.find_tls_groups.out".format(pdbFile) + ) + GroupNames = [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + ] + OutRefmac = "" + found = 0 + i = 0 + for line in open("phenix.find_tls_groups.out"): + if found: + if line.startswith("}"): + break + temp = [line.split()] + OutRefmac = ( + OutRefmac + + "\nTLS {0!s}\nRANGE ".format((GroupNames)[i]) + + str(temp[0][3])[:-1] + + " " + + str(temp[0][6]) + + ".' " + + str(temp[0][3])[:-1] + + " " + + str(temp[0][8]) + + ".' ALL\n" + ) + i += 1 + if line.startswith("refinement.refine.adp {"): + found = 1 + f = open("refmac.tls", "w") + f.write(OutRefmac) + f.close() + + OutPhenix = "" + found = 0 + for line in open("phenix.find_tls_groups.out"): + if found: + OutPhenix = OutPhenix + line + if line.startswith("}"): + break + if line.startswith("refinement.refine.adp {"): + found = 1 + OutPhenix = OutPhenix + line + f = open("phenix.tls", "w") + f.write(OutPhenix) + f.close() + + +if __name__ == "__main__": + pdbFile = sys.argv[1] + FindTLSgroups(pdbFile) diff --git a/xce/helpers/prepare_for_zenodo_upload.py b/xce/helpers/prepare_for_zenodo_upload.py new file mode 100755 index 00000000..0617d48c --- /dev/null +++ b/xce/helpers/prepare_for_zenodo_upload.py @@ -0,0 +1,132 @@ +import glob +import os +import sys + + +def copy_files(htmlDir): + os.chdir(htmlDir) + if not os.path.isdir("zenodo"): + os.mkdir("zenodo") + os.chdir(os.path.join(htmlDir, "zenodo")) + + print("copying compoundImages") + os.system("/bin/cp ../compoundImages/* .") + + print("copying pdbs") + os.system("/bin/cp ../pdbs/* .") + + print("copying maps") + os.system("/bin/cp ../maps/* .") + + print("copying residueplots") + os.system("/bin/cp ../residueplots/* .") + + print("copying mapImages") + os.system("/bin/cp ../mapImages/* .") + + print("copying icbs") + os.system("/bin/cp ../icbs/* .") + + print("copying css") + os.system("/bin/cp ../css/* .") + + print("copying js") + os.system("/bin/cp ../js/* .") + + +def edit_index_html(htmlDir, uploadID): + os.chdir(os.path.join(htmlDir, "zenodo")) + + out = "" + for line in open("../index.html"): + if "compoundImages/" in line: + line = line.replace( + "compoundImages/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "pdbs/" in line: + line = line.replace( + "pdbs/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "maps/" in line: + line = line.replace( + "maps/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "residueplots/" in line: + line = line.replace( + "residueplots/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "mapImages/" in line: + line = line.replace( + "mapImages/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "icbs/" in line: + line = line.replace( + "icbs/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "css/" in line: + line = line.replace( + "css/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "js/" in line: + line = line.replace( + "js/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + out += line + + print("writing index.html to", os.path.join(htmlDir, "zenodo")) + f = open("0_index.html", "w") + f.write(out) + f.close() + + +def edit_icb_html_files(htmlDir, uploadID): + # https://zenodo.org/record/48768/files/README.txt + os.chdir(os.path.join(htmlDir, "zenodo")) + for file in glob.glob("*event*html"): + out = "" + for line in open(file): + if 'src="http://molsoft.com/lib/acticm.js">' in line: + line = line.replace( + 'src="http://molsoft.com/lib/acticm.js">', + 'src="https://molsoft.com/lib/acticm.js">', + ) + if "../mapImages/" in line: + line = line.replace( + "../mapImages/", "https://zenodo.org/record/" + uploadID + "/files/" + ) + if "../compoundImages/" in line: + line = line.replace( + "../compoundImages/", + "https://zenodo.org/record/" + uploadID + "/files/", + ) + if ' act.projectFile = "' in line: + line = line.replace( + ' act.projectFile = "', + ' act.projectFile = "https://zenodo.org/record/' + + uploadID + + "/files/", + ) + out += line + print("updating", file) + f = open(file, "w") + f.write(out) + f.close() + + +if __name__ == "__main__": + print(len(sys.argv)) + + if len(sys.argv) == 2: + htmlDir = sys.argv[1] + if os.path.isdir(htmlDir): + copy_files(htmlDir) + + elif len(sys.argv) == 3: + htmlDir = sys.argv[1] + uploadID = sys.argv[2] + if os.path.isdir(htmlDir): + edit_index_html(htmlDir, uploadID) + edit_icb_html_files(htmlDir, uploadID) + + else: + print("wrong input!") diff --git a/xce/helpers/select_ground_state_dataset.py b/xce/helpers/select_ground_state_dataset.py new file mode 100755 index 00000000..ff5625a9 --- /dev/null +++ b/xce/helpers/select_ground_state_dataset.py @@ -0,0 +1,210 @@ +import glob +import os +import sys + +# - select datasets with highest resolution +# - select only those without an event map +# - take the one with the lowest Rfree + + +def find_highest_resolution_datasets(panddaDir): + found = False + datasetList = [] + for logFile in glob.glob(os.path.join(panddaDir, "logs", "*.log")): + for n, line in enumerate(open(logFile)): + if ( + line.startswith("Statistical Electron Density Characterisation") + and len(line.split()) == 6 + ): + found = True + foundLine = n + if found and n >= foundLine + 3: + if line.startswith("---"): + break + else: + tmpLine = ( + line.replace(" ", "") + .replace("\t", "") + .replace("\n", "") + .replace("\r", "") + ) + for item in tmpLine.split(","): + if item != "": + datasetList.append(item) + print(datasetList) + return datasetList + + +def get_datasets_without_event_map(panddaDir, datasetList): + datasetListwithoutEvent = [] + for dataset in datasetList: + noEvent = True + for files in glob.glob( + os.path.join(panddaDir, "processed_datasets", dataset, "*") + ): + if "event" in files: + noEvent = False + break + if noEvent: + datasetListwithoutEvent.append(dataset) + print(datasetListwithoutEvent) + return datasetListwithoutEvent + + +def select_dataset_with_lowest_Rfree(panddaDir, datasetListwithoutEvent): + datasetList = [] + lowestRfree = "" + for dataset in datasetListwithoutEvent: + if os.path.isfile( + os.path.join( + panddaDir, "processed_datasets", dataset, dataset + "-pandda-input.pdb" + ) + ): + stats = parse().PDBheader( + os.path.join( + panddaDir, + "processed_datasets", + dataset, + dataset + "-pandda-input.pdb", + ) + ) + Rfree = stats["Rfree"] + try: + print(dataset, Rfree, stats["ResolutionHigh"]) + datasetList.append([dataset, float(Rfree)]) + except ValueError: + pass + if datasetList: + lowestRfree = min(datasetList, key=lambda x: x[1])[0] + return lowestRfree + + +def link_pdb_mtz_files(panddaDir, lowestRfree): + targetDir = "/".join(panddaDir.split("/")[: len(panddaDir.split("/")) - 1]) + panddaFolder = panddaDir.split("/")[len(panddaDir.split("/")) - 1] + print(targetDir) + print(panddaFolder) + os.chdir(targetDir) + if os.path.isfile( + os.path.join( + panddaDir, + "processed_datasets", + lowestRfree, + lowestRfree + "-pandda-input.pdb", + ) + ): + os.system("/bin/rm %s-ground-state.pdb 2> /dev/null" % lowestRfree) + os.symlink( + os.path.join( + panddaFolder, + "processed_datasets", + lowestRfree, + lowestRfree + "-pandda-input.pdb", + ), + lowestRfree + "-ground-state.pdb", + ) + if os.path.isfile( + os.path.join( + panddaDir, + "processed_datasets", + lowestRfree, + lowestRfree + "-pandda-input.mtz", + ) + ): + os.system("/bin/rm %s-ground-state.free.mtz 2> /dev/null" % lowestRfree) + os.symlink( + os.path.join( + panddaFolder, + "processed_datasets", + lowestRfree, + lowestRfree + "-pandda-input.mtz", + ), + lowestRfree + "-ground-state.free.mtz", + ) + + if os.path.isfile( + os.path.join( + panddaDir, + "processed_datasets", + lowestRfree, + lowestRfree + "-ground-state-mean-map.native.ccp4", + ) + ): + os.system( + "/bin/rm %s-ground-state-mean-map.native.ccp4 2> /dev/null" % lowestRfree + ) + os.symlink( + os.path.join( + panddaFolder, + "processed_datasets", + lowestRfree, + lowestRfree + "-ground-state-mean-map.native.ccp4", + ), + lowestRfree + "-ground-state-mean-map.native.ccp4", + ) + elif os.path.isfile( + os.path.join( + panddaDir, + "processed_datasets", + lowestRfree, + lowestRfree + "-ground-state-average-map.native.ccp4", + ) + ): + os.system( + "/bin/rm %s-ground-state-mean-map.native.ccp4 2> /dev/null" % lowestRfree + ) + os.symlink( + os.path.join( + panddaFolder, + "processed_datasets", + lowestRfree, + lowestRfree + "-ground-state-average-map.native.ccp4", + ), + lowestRfree + "-ground-state-mean-map.native.ccp4", + ) + + convert_mean_map_to_mtz( + lowestRfree + "-ground-state-mean-map.native.ccp4", + lowestRfree + "-ground-state.free.mtz", + ) + + +def convert_mean_map_to_mtz(emap, mtz): + print("converting ground-state-mean-map to MTZ") + cmd = ( + "mapmask MAPIN %s MAPOUT %s << eof\n" + % (emap, emap.replace(".ccp4", ".P1.ccp4")) + + " XYZLIM CELL\n" + " PAD 0.0\n" + " SYMMETRY 1\n" + "eof\n" + ) + print(cmd) + os.system(cmd) + print("--->", mtz) + reso = mtztools(mtz).get_dmin() + print("-> resolution:", reso) + cmd = ( + "module load phenix/1.20\n" + "phenix.map_to_structure_factors %s d_min=%s\n" + % ( + emap.replace(".ccp4", ".P1.ccp4"), + reso, + ) + + "/bin/mv map_to_structure_factors.mtz %s" % emap.replace(".ccp4", ".mtz") + ) + print(cmd) + os.system(cmd) + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib.XChemUtils import mtztools, parse + + panddaDir = sys.argv[1] + datasetList = find_highest_resolution_datasets(panddaDir) + datasetListwithoutEvent = get_datasets_without_event_map(panddaDir, datasetList) + lowestRfree = select_dataset_with_lowest_Rfree(panddaDir, datasetListwithoutEvent) + link_pdb_mtz_files(panddaDir, lowestRfree) diff --git a/xce/helpers/update_data_source_after_refinement.py b/xce/helpers/update_data_source_after_refinement.py new file mode 100755 index 00000000..b162f6f2 --- /dev/null +++ b/xce/helpers/update_data_source_after_refinement.py @@ -0,0 +1,382 @@ +import csv +import glob +import os +import sys + + +def parse_pdb(inital_model_directory, xtal, db_dict): + if os.path.isfile(os.path.join(inital_model_directory, xtal, "refine.pdb")): + db_dict["RefinementPDB_latest"] = os.path.realpath( + os.path.join(inital_model_directory, xtal, "refine.pdb") + ) + pdb = parse().PDBheader( + os.path.join(inital_model_directory, xtal, "refine.pdb") + ) + db_dict["RefinementRcryst"] = pdb["Rcryst"] + db_dict["RefinementRcrystTraficLight"] = pdb["RcrystTL"] + db_dict["RefinementRfree"] = pdb["Rfree"] + db_dict["RefinementRfreeTraficLight"] = pdb["RfreeTL"] + db_dict["RefinementRmsdBonds"] = pdb["rmsdBonds"] + db_dict["RefinementRmsdBondsTL"] = pdb["rmsdBondsTL"] + db_dict["RefinementRmsdAngles"] = pdb["rmsdAngles"] + db_dict["RefinementRmsdAnglesTL"] = pdb["rmsdAnglesTL"] + db_dict["RefinementSpaceGroup"] = pdb["SpaceGroup"] + db_dict["RefinementResolution"] = pdb["ResolutionHigh"] + db_dict["RefinementResolutionTL"] = pdb["ResolutionColor"] + db_dict["RefinementStatus"] = "finished" + else: + db_dict["RefinementStatus"] = "failed" + + if os.path.isfile(os.path.join(inital_model_directory, xtal, "refine.bound.pdb")): + db_dict["RefinementBoundConformation"] = os.path.realpath( + os.path.join(inital_model_directory, xtal, "refine.bound.pdb") + ) + elif os.path.isfile( + os.path.join(inital_model_directory, xtal, "refine.split.bound-state.pdb") + ): + db_dict["RefinementBoundConformation"] = os.path.realpath( + os.path.join(inital_model_directory, xtal, "refine.split.bound-state.pdb") + ) + elif os.path.isfile(os.path.join(inital_model_directory, xtal, "refine.pdb")): + db_dict["RefinementBoundConformation"] = os.path.realpath( + os.path.join(inital_model_directory, xtal, "refine.pdb") + ) + + print(db_dict) + + return db_dict + + +def parse_mtz(inital_model_directory, xtal, db_dict): + if os.path.isfile(os.path.join(inital_model_directory, xtal, "refine.mtz")): + db_dict["RefinementMTZ_latest"] = os.path.realpath( + os.path.join(inital_model_directory, xtal, "refine.mtz") + ) + return db_dict + + +def check_refmac_matrix_weight(refinement_directory, db_dict): + if os.path.isfile(os.path.join(refinement_directory, "refmac.log")): + logFile = os.path.join(refinement_directory, "refmac.log") + else: + logFile = "" + for files in glob.glob(os.path.join(refinement_directory, "*refine.log")): + logFile = files + break + if os.path.isfile(logFile): + for line in open(logFile): + if line.startswith(" Weight matrix") and len(line.split()) == 3: + db_dict["RefinementMatrixWeight"] = line.split()[2] + return db_dict + + +def check_refmac_logfile(refinement_directory, db_dict): + if os.path.isfile(os.path.join(refinement_directory, "refmac.log")): + logFile = os.path.join(refinement_directory, "refmac.log") + else: + logFile = "" + for files in glob.glob(os.path.join(refinement_directory, "*refine.log")): + logFile = files + break + if os.path.isfile(logFile): + for line in open(logFile): + if ( + "Your coordinate file has a ligand which has either minimum" + " or no description in the library" in line + ): + db_dict["RefinementStatus"] = "CIF problem" + return db_dict + + +def parse_molprobity_output(inital_model_directory, xtal, db_dict): + if os.path.isfile( + os.path.join(inital_model_directory, xtal, "validation_summary.txt") + ): + for line in open( + os.path.join(inital_model_directory, xtal, "validation_summary.txt") + ): + if "molprobity score" in line.lower(): + if len(line.split()) >= 4: + db_dict["RefinementMolProbityScore"] = line.split()[3] + if float(line.split()[3]) < 2: + db_dict["RefinementMolProbityScoreTL"] = "green" + if 2 <= float(line.split()[3]) < 3: + db_dict["RefinementMolProbityScoreTL"] = "orange" + if float(line.split()[3]) >= 3: + db_dict["RefinementMolProbityScoreTL"] = "red" + + if "ramachandran outliers" in line.lower(): + if len(line.split()) >= 4: + db_dict["RefinementRamachandranOutliers"] = line.split()[3] + + if float(line.split()[3]) < 0.3: + db_dict["RefinementRamachandranOutliersTL"] = "green" + if 0.3 <= float(line.split()[3]) < 1: + db_dict["RefinementRamachandranOutliersTL"] = "orange" + if float(line.split()[3]) >= 1: + db_dict["RefinementRamachandranOutliersTL"] = "red" + + if "favored" in line.lower(): + if len(line.split()) >= 3: + db_dict["RefinementRamachandranFavored"] = line.split()[2] + if float(line.split()[2]) < 90: + db_dict["RefinementRamachandranFavoredTL"] = "red" + if 90 <= float(line.split()[2]) < 98: + db_dict["RefinementRamachandranFavoredTL"] = "orange" + if float(line.split()[2]) >= 98: + db_dict["RefinementRamachandranFavoredTL"] = "green" + + return db_dict + + +def parse_ligand_validation(inital_model_directory, refinement_directory, xtal): + if os.path.isfile(os.path.join(refinement_directory, "residue_scores.csv")): + with open( + os.path.join(refinement_directory, "residue_scores.csv"), "rb" + ) as csv_import: + csv_dict = csv.DictReader(csv_import) + for i, line in enumerate(csv_dict): + db_pandda_dict = {} + residue = line[""].replace(" ", "") + residueFilename = line[""] + if len(residue.split("-")) == 2: + # residue_name = residue.split('-')[0] + # print residue_name + residue_chain = residue.split("-")[0] + residue_number = residue.split("-")[1] + residue_xyz = pdbtools( + os.path.join(inital_model_directory, xtal, "refine.pdb") + ).get_center_of_gravity_of_residue_ish( + residue_chain, residue_number + ) + event = db.execute_statement( + "select PANDDA_site_x," + "PANDDA_site_y," + "PANDDA_site_z," + "PANDDA_site_index" + " from panddaTable where CrystalName='{0!s}'".format(xtal) + ) + for coord in event: + db_pandda_dict = {} + event_x = float(str(coord[0])) + event_y = float(str(coord[1])) + event_z = float(str(coord[2])) + site_index = str(coord[3]) + distance = calculate_distance_between_coordinates( + residue_xyz[0], + residue_xyz[1], + residue_xyz[2], + event_x, + event_y, + event_z, + ) + print("distance", distance) + # if coordinate of ligand and event are closer than 7A + # then we assume they belong together + if distance < 7: + db_pandda_dict["PANDDA_site_ligand_id"] = residue + db_pandda_dict["PANDDA_site_occupancy"] = line["Occupancy"] + db_pandda_dict["PANDDA_site_B_average"] = line[ + "Average B-factor (Residue)" + ] + db_pandda_dict[ + "PANDDA_site_B_ratio_residue_surroundings" + ] = line["Surroundings B-factor Ratio"] + db_pandda_dict["PANDDA_site_rmsd"] = line["Model RMSD"] + db_pandda_dict["PANDDA_site_RSCC"] = line["RSCC"] + db_pandda_dict["PANDDA_site_RSR"] = line["RSR"] + db_pandda_dict["PANDDA_site_RSZD"] = line["RSZD"] + if os.path.isfile( + os.path.join( + refinement_directory, + "residue_plots", + residueFilename + ".png", + ) + ): + db_pandda_dict[ + "PANDDA_site_spider_plot" + ] = os.path.join( + refinement_directory, + "residue_plots", + residueFilename + ".png", + ) + else: + db_pandda_dict["PANDDA_site_spider_plot"] = "" + + if db_pandda_dict != {}: + print("==> XCE: updating pandda Table of data source") + db.update_panddaTable(xtal, site_index, db_pandda_dict) + + +def update_ligand_information_in_panddaTable(inital_model_directory, xtal): + if os.path.isfile(os.path.join(inital_model_directory, xtal, "refine.pdb")): + ligands_in_file = pdbtools( + os.path.join(inital_model_directory, xtal, "refine.pdb") + ).get_residues_with_resname("LIG") + for ligand in ligands_in_file: + residue_name = ligand[0] + residue_chain = ligand[2] + residue_number = ligand[1] + residue_altLoc = "X" + residue_xyz = pdbtools( + os.path.join(inital_model_directory, xtal, "refine.pdb") + ).get_center_of_gravity_of_residue_ish(residue_chain, residue_number) + event = db.execute_statement( + "select PANDDA_site_x," + "PANDDA_site_y," + "PANDDA_site_z," + "PANDDA_site_index" + " from panddaTable where CrystalName='{0!s}'".format(xtal) + ) + for coord in event: + db_pandda_dict = {} + event_x = float(str(coord[0])) + event_y = float(str(coord[1])) + event_z = float(str(coord[2])) + site_index = str(coord[3]) + distance = calculate_distance_between_coordinates( + residue_xyz[0], + residue_xyz[1], + residue_xyz[2], + event_x, + event_y, + event_z, + ) + # if coordinate of ligand and event are closer than 7A + # then we assume they belong together + if distance < 7: + db_pandda_dict["PANDDA_site_ligand_resname"] = residue_name + db_pandda_dict["PANDDA_site_ligand_chain"] = residue_chain + db_pandda_dict[ + "PANDDA_site_ligand_sequence_number" + ] = residue_number + db_pandda_dict["PANDDA_site_ligand_altLoc"] = residue_altLoc + db_pandda_dict["PANDDA_site_ligand_placed"] = "True" + if db_pandda_dict != {}: + print("==> XCE: updating pandda Table of data source") + db.update_panddaTable(xtal, site_index, db_pandda_dict) + + +def update_data_source(db_dict): + if db_dict != {}: + print("==> xce: updating mainTable of data source") + db.update_data_source(xtal, db_dict) + # update refinement outcome if necessary + sqlite = ( + "update mainTable set RefinementOutcome =" + " '3 - In Refinement' where CrystalName is '{0!s}' ".format(xtal) + + "and (RefinementOutcome is null" + " or RefinementOutcome is '1 - Analysis Pending'" + " or RefinementOutcome is '2 - PANDDA model')" + ) + db.execute_statement(sqlite) + # now do the same for each site in the pandda table + sqlite = ( + "update panddaTable set RefinementOutcome =" + " '3 - In Refinement' where CrystalName is '{0!s}' ".format(xtal) + + "and (RefinementOutcome is null" + " or RefinementOutcome is '1 - Analysis Pending'" + " or RefinementOutcome is '2 - PANDDA model')" + ) + db.execute_statement(sqlite) + + +def update_buster_report_index_html(refinement_directory, db_dict): + if os.path.isfile(refinement_directory + "-report/index.html"): + db_dict["RefinementBusterReportHTML"] = ( + refinement_directory + "-report/index.html" + ) + return db_dict + + +def update_mmcif_file_location(refinement_directory, db_dict): + if os.path.isfile(os.path.join(refinement_directory, "BUSTER_model.cif")): + db_dict["RefinementMMCIFmodel_latest"] = os.path.join( + refinement_directory, "BUSTER_model.cif" + ) + if os.path.isfile(os.path.join(refinement_directory, "BUSTER_refln.cif")): + db_dict["RefinementMMCIFreflections_latest"] = os.path.join( + refinement_directory, "BUSTER_refln.cif" + ) + return db_dict + + +def generate_cut_maps_around_ligand(xtal): + if ( + os.path.isfile(os.path.join(inital_model_directory, xtal, "refine.pdb")) + and os.path.isfile(os.path.join(inital_model_directory, xtal, "2fofc.map")) + and os.path.isfile(os.path.join(inital_model_directory, xtal, "fofc.map")) + ): + ligandDict = pdbtools_gemmi("refine.pdb").center_of_mass_ligand_dict("LIG") + pdbtools_gemmi("refine.pdb").save_ligands_to_pdb("LIG") + for ligand in ligandDict: + maptools().cut_map_around_ligand("2fofc.map", ligand + ".pdb", "7") + os.system("/bin/mv 2fofc_mapmask.map %s_%s_2fofc_cut.ccp4" % (xtal, ligand)) + maptools().cut_map_around_ligand("fofc.map", ligand + ".pdb", "7") + os.system("/bin/mv fofc_mapmask.map %s_%s_fofc_cut.ccp4" % (xtal, ligand)) + + +def read_ligand_cc_from_edstats(xtal, db_dict): + ligCC = "" + if os.path.isfile(os.path.join(inital_model_directory, xtal, "refine.edstats")): + ligandDict = pdbtools_gemmi("refine.pdb").center_of_mass_ligand_dict("LIG") + for ligand in ligandDict: + lig = ligand.split("-")[0] + chain = ligand.split("-")[1] + resn = ligand.split("-")[2] + for line in open("refine.edstats"): + if ( + line.startswith(lig) + and line.split()[1] == chain + and line.split()[2] == str(resn) + ): + try: + cc = line.split()[8] + ligCC += ligand + ": " + cc + "\n" + except IndexError: + continue + break + db_dict["RefinementLigandCC"] = ligCC.rstrip() + return db_dict + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import XChemDB + from xce.lib.XChemUtils import ( + calculate_distance_between_coordinates, + maptools, + parse, + pdbtools, + pdbtools_gemmi, + ) + + db_file = sys.argv[1] + xtal = sys.argv[2] + inital_model_directory = sys.argv[3] + refinement_directory = sys.argv[4] + refiner = sys.argv[5] + date = sys.argv[6] + + db = XChemDB.data_source(db_file) + db_dict = {} + db_dict["RefinementRefiner"] = refiner + db_dict["RefinementDate"] = date + + db_dict = parse_pdb(inital_model_directory, xtal, db_dict) + db_dict = parse_mtz(inital_model_directory, xtal, db_dict) + db_dict = check_refmac_matrix_weight(refinement_directory, db_dict) + db_dict = parse_molprobity_output(inital_model_directory, xtal, db_dict) + db_dict = check_refmac_logfile(refinement_directory, db_dict) + db_dict = update_buster_report_index_html(refinement_directory, db_dict) + db_dict = update_mmcif_file_location(refinement_directory, db_dict) + db_dict = read_ligand_cc_from_edstats(xtal, db_dict) + update_ligand_information_in_panddaTable(inital_model_directory, xtal) + + parse_ligand_validation(inital_model_directory, refinement_directory, xtal) + + update_data_source(db_dict) + + generate_cut_maps_around_ligand(xtal) diff --git a/xce/helpers/update_data_source_for_new_cif_files.py b/xce/helpers/update_data_source_for_new_cif_files.py new file mode 100755 index 00000000..0fa01cbb --- /dev/null +++ b/xce/helpers/update_data_source_for_new_cif_files.py @@ -0,0 +1,53 @@ +import os +import sys + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import XChemDB + + db_file = sys.argv[1] + xtal = sys.argv[2] + initial_model_directory = sys.argv[3] + compoundID = sys.argv[4] + + db = XChemDB.data_source(db_file) + db_dict = {} + if ( + os.path.isfile( + os.path.join(initial_model_directory, xtal, "compound", compoundID + ".cif") + ) + and os.path.getsize( + os.path.join(initial_model_directory, xtal, "compound", compoundID + ".cif") + ) + > 20 + ): + db_dict["RefinementCIF"] = os.path.join( + initial_model_directory, xtal, "compound", compoundID + ".cif" + ) + db_dict["RefinementCIFStatus"] = "restraints generated" + else: + db_dict["RefinementCIF"] = "" + db_dict["RefinementCIFStatus"] = "restraints failed" + os.system( + "/bin/rm " + + os.path.join( + initial_model_directory, xtal, compoundID.replace(" ", "") + ".pdb" + ) + ) + os.system( + "/bin/rm " + + os.path.join( + initial_model_directory, xtal, compoundID.replace(" ", "") + ".cif" + ) + ) + os.system( + "/bin/rm " + + os.path.join( + initial_model_directory, xtal, compoundID.replace(" ", "") + ".png" + ) + ) + + db.update_data_source(xtal, db_dict) diff --git a/xce/helpers/update_data_source_for_new_dimple_pdb.py b/xce/helpers/update_data_source_for_new_dimple_pdb.py new file mode 100755 index 00000000..4386cb0d --- /dev/null +++ b/xce/helpers/update_data_source_for_new_dimple_pdb.py @@ -0,0 +1,150 @@ +import os +import sys + +from iotbx import mtz + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import XChemDB + from xce.lib.XChemUtils import parse + + db_file = sys.argv[1] + xtal = sys.argv[2] + inital_model_directory = sys.argv[3] + + db = XChemDB.data_source(db_file) + if os.path.isfile(os.path.join(inital_model_directory, xtal, "dimple.pdb")): + db_dict = { + "DimplePathToPDB": os.path.join(inital_model_directory, xtal, "dimple.pdb") + } + dimple_ran_successfully = False + if os.path.isfile(os.path.join(inital_model_directory, xtal, "dimple.mtz")): + db_dict["DimplePathToMTZ"] = os.path.join( + inital_model_directory, xtal, "dimple.mtz" + ) + dimple_ran_successfully = True + db_dict["DataProcessingDimpleSuccessful"] = "True" + db_dict["DimpleStatus"] = "finished" + if not dimple_ran_successfully: + db_dict["DataProcessingDimpleSuccessful"] = "False" + db_dict["DimpleStatus"] = "failed" + pdb = parse().PDBheader( + os.path.join(inital_model_directory, xtal, "dimple.pdb") + ) + db_dict["DimpleRcryst"] = pdb["Rcryst"] + db_dict["DimpleRfree"] = pdb["Rfree"] + db_dict["RefinementOutcome"] = "1 - Analysis Pending" + db_dict["RefinementSpaceGroup"] = pdb["SpaceGroup"] + + # setting free.mtz file + os.chdir(os.path.join(inital_model_directory, xtal)) + os.system("/bin/rm -f %s.free.mtz" % xtal) + mtzFree = None + db_dict["RefinementMTZfree"] = "" + if os.path.isfile( + os.path.join( + inital_model_directory, + xtal, + "dimple", + "dimple_rerun_on_selected_file", + "dimple", + "prepared2.mtz", + ) + ): + mtzFree = os.path.join( + inital_model_directory, + xtal, + "dimple", + "dimple_rerun_on_selected_file", + "dimple", + "prepared2.mtz", + ) + elif os.path.isfile( + os.path.join( + inital_model_directory, + xtal, + "dimple", + "dimple_rerun_on_selected_file", + "dimple", + "prepared.mtz", + ) + ): + mtzFree = os.path.join( + inital_model_directory, + xtal, + "dimple", + "dimple_rerun_on_selected_file", + "dimple", + "prepared.mtz", + ) + elif os.path.isfile( + os.path.join( + inital_model_directory, xtal, "dimple", "dimple", "prepared.mtz" + ) + ): + mtzFree = os.path.join( + inital_model_directory, xtal, "dimple", "dimple", "prepared.mtz" + ) + elif os.path.isfile( + os.path.join( + inital_model_directory, xtal, "dimple", "dimple", "prepared2.mtz" + ) + ): + mtzFree = os.path.join( + inital_model_directory, xtal, "dimple", "dimple", "prepared2.mtz" + ) + elif os.path.isfile( + os.path.join( + inital_model_directory, + xtal, + "dimple", + "dimple_rerun_on_selected_file", + "dimple", + "free.mtz", + ) + ): + mtzFree = os.path.join( + inital_model_directory, + xtal, + "dimple", + "dimple_rerun_on_selected_file", + "dimple", + "free.mtz", + ) + elif os.path.isfile( + os.path.join(inital_model_directory, xtal, "dimple", "dimple", "free.mtz") + ): + mtzFree = os.path.join( + inital_model_directory, xtal, "dimple", "dimple", "free.mtz" + ) + + if mtzFree is not None: + if "F_unique" in mtz.object(mtzFree).column_labels(): + cmd = ( + "cad hklin1 %s hklout %s.free.mtz << eof\n" % (mtzFree, xtal) + + " monitor BRIEF\n" + " labin file 1 E1=F E2=SIGF E3=FreeR_flag\n" + " labout file 1 E1=F E2=SIGF E3=FreeR_flag\n" + "eof\n" + ) + + os.system(cmd) + else: + os.symlink(mtzFree, xtal + ".free.mtz") + + db_dict["RefinementMTZfree"] = xtal + ".free.mtz" + + print("==> xce: updating data source after DIMPLE run") + db.update_data_source(xtal, db_dict) + + else: + # the actual dimple script creates symbolic links regardless if dimple was + # successful or not python os.path.isfile is False if symbolic link points to + # non existing file so we remove all of them! + os.chdir(os.path.join(inital_model_directory, xtal)) + os.system("/bin/rm dimple.pdb") + os.system("/bin/rm dimple.mtz") + os.system("/bin/rm 2fofc.map") + os.system("/bin/rm fofc.map") diff --git a/xce/helpers/update_status_flag.py b/xce/helpers/update_status_flag.py new file mode 100755 index 00000000..7a3858e6 --- /dev/null +++ b/xce/helpers/update_status_flag.py @@ -0,0 +1,22 @@ +import os +import sys + + +def update_data_source(db_file, xtal, db_column, status): + db = XChemDB.data_source(db_file) + db_dict = {db_column: status} + db.update_data_source(xtal, db_dict) + + +if __name__ == "__main__": + sys.path.insert( + 0, os.path.join(os.environ["XChemExplorer_DIR"], "dist", "xce-2.0.1-py2.7.egg") + ) + from xce.lib import XChemDB + + db_file = sys.argv[1] + xtal = sys.argv[2] + db_column = sys.argv[3] + status = sys.argv[4] + + update_data_source(db_file, xtal, db_column, status) diff --git a/icons/001-ducky.png b/xce/icons/001-ducky.png similarity index 100% rename from icons/001-ducky.png rename to xce/icons/001-ducky.png diff --git a/icons/002-chinese-panda-bear.png b/xce/icons/002-chinese-panda-bear.png similarity index 100% rename from icons/002-chinese-panda-bear.png rename to xce/icons/002-chinese-panda-bear.png diff --git a/icons/003-internet.png b/xce/icons/003-internet.png similarity index 100% rename from icons/003-internet.png rename to xce/icons/003-internet.png diff --git a/icons/004-database-configuration.png b/xce/icons/004-database-configuration.png similarity index 100% rename from icons/004-database-configuration.png rename to xce/icons/004-database-configuration.png diff --git a/icons/005-sort-down.png b/xce/icons/005-sort-down.png similarity index 100% rename from icons/005-sort-down.png rename to xce/icons/005-sort-down.png diff --git a/icons/006-sort-up.png b/xce/icons/006-sort-up.png similarity index 100% rename from icons/006-sort-up.png rename to xce/icons/006-sort-up.png diff --git a/icons/drop-down-round-button.png b/xce/icons/drop-down-round-button.png similarity index 100% rename from icons/drop-down-round-button.png rename to xce/icons/drop-down-round-button.png diff --git a/icons/drop-down.png b/xce/icons/drop-down.png similarity index 100% rename from icons/drop-down.png rename to xce/icons/drop-down.png diff --git a/image/IMAGE_NOT_AVAILABLE.png b/xce/image/IMAGE_NOT_AVAILABLE.png similarity index 100% rename from image/IMAGE_NOT_AVAILABLE.png rename to xce/image/IMAGE_NOT_AVAILABLE.png diff --git a/image/NO_COMPOUND_IMAGE_AVAILABLE.png b/xce/image/NO_COMPOUND_IMAGE_AVAILABLE.png similarity index 100% rename from image/NO_COMPOUND_IMAGE_AVAILABLE.png rename to xce/image/NO_COMPOUND_IMAGE_AVAILABLE.png diff --git a/image/NO_REFINEMENT_HISTORY_AVAILABLE.png b/xce/image/NO_REFINEMENT_HISTORY_AVAILABLE.png similarity index 100% rename from image/NO_REFINEMENT_HISTORY_AVAILABLE.png rename to xce/image/NO_REFINEMENT_HISTORY_AVAILABLE.png diff --git a/image/NO_SPIDER_PLOT_AVAILABLE.png b/xce/image/NO_SPIDER_PLOT_AVAILABLE.png similarity index 100% rename from image/NO_SPIDER_PLOT_AVAILABLE.png rename to xce/image/NO_SPIDER_PLOT_AVAILABLE.png diff --git a/image/drag_and_drop_icb_file.png b/xce/image/drag_and_drop_icb_file.png similarity index 100% rename from image/drag_and_drop_icb_file.png rename to xce/image/drag_and_drop_icb_file.png diff --git a/image/html_summary_page.png b/xce/image/html_summary_page.png similarity index 100% rename from image/html_summary_page.png rename to xce/image/html_summary_page.png diff --git a/image/new_zenodo_upload.png b/xce/image/new_zenodo_upload.png similarity index 100% rename from image/new_zenodo_upload.png rename to xce/image/new_zenodo_upload.png diff --git a/image/run_icm_script.png b/xce/image/run_icm_script.png similarity index 100% rename from image/run_icm_script.png rename to xce/image/run_icm_script.png diff --git a/image/zenodo_upload_id.png b/xce/image/zenodo_upload_id.png similarity index 100% rename from image/zenodo_upload_id.png rename to xce/image/zenodo_upload_id.png diff --git a/xce/lib/XChemDB.py b/xce/lib/XChemDB.py new file mode 100755 index 00000000..d53e666d --- /dev/null +++ b/xce/lib/XChemDB.py @@ -0,0 +1,1859 @@ +import csv +import getpass +import sqlite3 +from datetime import datetime + +from xce.lib import XChemLog + +# from XChemUtils import parse + + +class data_source: + def __init__(self, data_source_file): + self.data_source_file = data_source_file + + # [column_name in DB, column_name shown in XCE, SQLite column type] + self.column_list = [ + # SQLite column name | XCE column name | SQLite type | in overview tab + # from Lab36 + ["ID", "ID", "INTEGER PRIMARY KEY", 0], + ["LabVisit", "LabVisit", "TEXT", 1], + ["LibraryPlate", "LibraryPlate", "TEXT", 0], + ["SourceWell", "SourceWell", "TEXT", 0], + ["LibraryName", "LibraryName", "TEXT", 1], + ["CompoundSMILES", "Smiles", "TEXT", 1], + ["CompoundSMILESproduct", "Smiles - Product", "TEXT", 1], + ["CompoundCode", "Compound ID", "TEXT", 1], + ["CompoundStereo", "Compound Stereo", "TEXT", 1], + ["CompoundStereoSMILES", "Stereo SMILES", "TEXT", 1], + ["CompoundStereoCIFprogram", "Stereo CIF program", "TEXT", 1], + ["CompoundStereoCIFs", "Compound Stereo IDs", "TEXT", 1], + ["CompoundAutofitCC", "autofit CC", "TEXT", 1], + ["CompoundAutofitprogram", "autofit program", "TEXT", 1], + ["CrystalPlate", "CrystalPlate", "TEXT", 1], + ["CrystalWell", "CrystalWell", "TEXT", 1], + ["EchoX", "EchoX", "TEXT", 0], + ["EchoY", "EchoY", "TEXT", 0], + ["DropVolume", "DropVolume", "TEXT", 0], + ["ProteinName", "ProteinName", "TEXT", 1], + ["BatchNumber", "BatchNumber", "TEXT", 0], + ["CompoundStockConcentration", "CompoundStockConcentration", "TEXT", 0], + ["CompoundConcentration", "CompoundConcentration", "TEXT", 1], + ["SolventFraction", "SolventFraction", "TEXT", 1], + ["SoakTransferVol", "SoakTransferVol", "TEXT", 0], + ["SoakStatus", "SoakStatus", "TEXT", 0], + ["SoakTimestamp", "SoakTimestamp", "TEXT", 0], + ["CryoStockFraction", "CryoStockFraction", "TEXT", 0], + ["CryoFraction", "CryoFraction", "TEXT", 0], + ["CryoWell", "CryoWell", "TEXT", 0], + ["CryoTransferVolume", "CryoTransferVolume", "TEXT", 0], + ["CryoStatus", "CryoStatus", "TEXT", 0], + ["CryoTimestamp", "CryoTimestamp", "TEXT", 0], + ["SoakingTime", "SoakingTime", "TEXT", 1], + ["HarvestStatus", "HarvestStatus", "TEXT", 0], + ["CrystalName", "Sample ID", "TEXT", 0], + ["Puck", "Puck", "TEXT", 1], + ["PuckPosition", "PuckPosition", "TEXT", 1], + ["PinBarcode", "SoakDB\nBarcode", "TEXT", 1], + ["MountingResult", "MountingResult", "TEXT", 0], + ["MountingArrivalTime", "MountingArrivalTime", "TEXT", 0], + ["MountedTimestamp", "MountedTimestamp", "TEXT", 0], + ["MountingTime", "MountingTime", "TEXT", 0], + ["ispybStatus", "ispybStatus", "TEXT", 0], + ["DataCollectionVisit", "Visit", "TEXT", 1], + # from XChemExplorer + ["ProjectDirectory", "ProjectDirectory", "TEXT", 0], + ["CrystalTag", "Tag", "TEXT", 0], + ["CrystalFormName", "Crystal Form\nName", "TEXT", 0], + ["CrystalFormSpaceGroup", "Space\nGroup", "TEXT", 0], + ["CrystalFormPointGroup", "Point\nGroup", "TEXT", 0], + ["CrystalFormA", "a", "TEXT", 0], + ["CrystalFormB", "b", "TEXT", 0], + ["CrystalFormC", "c", "TEXT", 0], + ["CrystalFormAlpha", "alpha", "TEXT", 0], + ["CrystalFormBeta", "beta", "TEXT", 0], + ["CrystalFormGamma", "gamma", "TEXT", 0], + ["CrystalFormVolume", "Crystal Form\nVolume", "TEXT", 0], + ["DataCollectionBeamline", "Beamline", "TEXT", 0], + ["DataCollectionDate", "Data Collection\nDate", "TEXT", 1], + ["DataCollectionOutcome", "DataCollection\nOutcome", "TEXT", 1], + ["DataCollectionRun", "Run", "TEXT", 0], + ["DataCollectionSubdir", "SubDir", "TEXT", 0], + ["DataCollectionComment", "DataCollection\nComment", "TEXT", 0], + ["DataCollectionWavelength", "Wavelength", "TEXT", 0], + ["DataCollectionPinBarcode", "GDA\nBarcode", "TEXT", 1], + ["DataCollectionCrystalImage1", "img1", "TEXT", 1], + ["DataCollectionCrystalImage2", "img2", "TEXT", 1], + ["DataCollectionCrystalImage3", "img3", "TEXT", 1], + ["DataCollectionCrystalImage4", "img4", "TEXT", 1], + [ + "DataProcessingPathToImageFiles", + "Path to diffraction\nimage files", + "TEXT", + 1, + ], + ["DataProcessingProgram", "Program", "TEXT", 1], + ["DataProcessingSpaceGroup", "DataProcessing\nSpaceGroup", "TEXT", 1], + ["DataProcessingUnitCell", "DataProcessing\nUnitCell", "TEXT", 0], + ["DataProcessingAutoAssigned", "auto-assigned", "TEXT", 0], + ["DataProcessingA", "DataProcessing\nA", "TEXT", 0], + ["DataProcessingB", "DataProcessing\nB", "TEXT", 0], + ["DataProcessingC", "DataProcessing\nC", "TEXT", 0], + ["DataProcessingAlpha", "DataProcessing\nAlpha", "TEXT", 0], + ["DataProcessingBeta", "DataProcessing\nBeta", "TEXT", 0], + ["DataProcessingGamma", "DataProcessing\nGamma", "TEXT", 0], + ["DataProcessingResolutionOverall", "Resolution\nOverall", "TEXT", 0], + ["DataProcessingResolutionLow", "Resolution\nLow", "TEXT", 0], + [ + "DataProcessingResolutionLowInnerShell", + "Resolution\nLow (Inner Shell)", + "TEXT", + 0, + ], + ["DataProcessingResolutionHigh", "Resolution\nHigh", "TEXT", 1], + [ + "DataProcessingResolutionHigh15sigma", + "Resolution\n[Mn = 1.5]", + "TEXT", + 1, + ], + [ + "DataProcessingResolutionHigh20sigma", + "Resolution\n[Mn = 2.0]", + "TEXT", + 1, + ], + [ + "DataProcessingResolutionHighOuterShell", + "Resolution\nHigh (Outer Shell)", + "TEXT", + 0, + ], + ["DataProcessingRmergeOverall", "Rmerge\nOverall", "TEXT", 1], + ["DataProcessingRmergeLow", "Rmerge\nLow", "TEXT", 1], + ["DataProcessingRmergeHigh", "Rmerge\nHigh", "TEXT", 1], + ["DataProcessingIsigOverall", "Mn\nOverall", "TEXT", 1], + ["DataProcessingIsigLow", "Mn\nLow", "TEXT", 1], + ["DataProcessingIsigHigh", "Mn\nHigh", "TEXT", 1], + ["DataProcessingCompletenessOverall", "Completeness\nOverall", "TEXT", 1], + ["DataProcessingCompletenessLow", "Completeness\nLow", "TEXT", 1], + ["DataProcessingCompletenessHigh", "Completeness\nHigh", "TEXT", 1], + ["DataProcessingMultiplicityOverall", "Multiplicity\nOverall", "TEXT", 1], + ["DataProcessingMultiplicityLow", "Multiplicity\nLow", "TEXT", 1], + ["DataProcessingMultiplicityHigh", "Multiplicity\nHigh", "TEXT", 1], + ["DataProcessingCChalfOverall", "CC(1/2)\nOverall", "TEXT", 1], + ["DataProcessingCChalfLow", "CC(1/2)\nLow", "TEXT", 1], + ["DataProcessingCChalfHigh", "CC(1/2)\nHigh", "TEXT", 1], + # the data source is a bit exploding with entries like the ones below, + # but the many different filenames and folder structures of Diamond + # autoprocessing makes it necessary + ["DataProcessingPathToLogfile", "DataProcessingPathToLogfile", "TEXT", 1], + ["DataProcessingPathToMTZfile", "DataProcessingPathToMTZfile", "TEXT", 1], + ["DataProcessingLOGfileName", "DataProcessingLOGfileName", "TEXT", 0], + ["DataProcessingMTZfileName", "DataProcessingMTZfileName", "TEXT", 0], + [ + "DataProcessingDirectoryOriginal", + "DataProcessingDirectoryOriginal", + "TEXT", + 0, + ], + [ + "DataProcessingUniqueReflectionsOverall", + "Unique Reflections\nOverall", + "TEXT", + 1, + ], + [ + "DataProcessingUniqueReflectionsLow", + "Unique Reflections\nlow", + "TEXT", + 1, + ], + [ + "DataProcessingUniqueReflectionsHigh", + "Unique Reflections\nhigh", + "TEXT", + 1, + ], + ["DataProcessingLattice", "DataProcessing\nLattice", "TEXT", 0], + ["DataProcessingPointGroup", "DataProcessing\nPointGroup", "TEXT", 0], + [ + "DataProcessingUnitCellVolume", + "DataProcessing\nUnit Cell Volume", + "TEXT", + 0, + ], + ["DataProcessingAlert", "DataProcessing\nAlert", "TEXT", 0], + ["DataProcessingScore", "DataProcessing\nScore", "TEXT", 1], + ["DataProcessingStatus", "DataProcessing\nStatus", "TEXT", 1], + ["DataProcessingRcryst", "DataProcessing\nRcryst", "TEXT", 0], + ["DataProcessingRfree", "DataProcessing\nRfree", "TEXT", 0], + [ + "DataProcessingPathToDimplePDBfile", + "DataProcessingPathToDimplePDBfile", + "TEXT", + 0, + ], + [ + "DataProcessingPathToDimpleMTZfile", + "DataProcessingPathToDimpleMTZfile", + "TEXT", + 0, + ], + [ + "DataProcessingDimpleSuccessful", + "DataProcessingDimpleSuccessful", + "TEXT", + 0, + ], + ["DimpleResolutionHigh", "Dimple\nResolution High", "TEXT", 1], + ["DimpleRcryst", "Dimple\nRcryst", "TEXT", 1], + ["DimpleRfree", "Dimple\nRfree", "TEXT", 1], + ["DimplePathToPDB", "Dimple\nPath to PDB file", "TEXT", 1], + ["DimplePathToMTZ", "Dimple\nPath to MTZ file", "TEXT", 1], + ["DimpleReferencePDB", "Dimple\nReference PDB", "TEXT", 1], + ["DimpleStatus", "Dimple\nStatus", "TEXT", 1], + ["DimpleTwinResolutionHigh", "Dimple - twin\nResolution High", "TEXT", 1], + ["DimpleTwinRcryst", "Dimple - twin\nRcryst", "TEXT", 1], + ["DimpleTwinRfree", "Dimple - twin\nRfree", "TEXT", 1], + ["DimpleTwinPathToPDB", "Dimple - twin\nPath to PDB file", "TEXT", 1], + ["DimpleTwinPathToMTZ", "Dimple - twin\nPath to MTZ file", "TEXT", 1], + ["DimpleTwinReferencePDB", "Dimple - twin\nReference PDB", "TEXT", 1], + ["DimpleTwinStatus", "Dimple - twin\nStatus", "TEXT", 1], + ["DimpleTwinFraction", "Dimple - twin\nFraction", "TEXT", 1], + [ + "DataProcessingDimpleTwinSuccessful", + "DataProcessingDimpleTwinSuccessful", + "TEXT", + 0, + ], + ["DimplePANDDAwasRun", "PanDDA\nlaunched?", "TEXT", 1], + ["DimplePANDDAhit", "PanDDA\nhit?", "TEXT", 1], + ["DimplePANDDAreject", "PanDDA\nreject?", "TEXT", 1], + ["DimplePANDDApath", "PanDDA\npath?", "TEXT", 1], + ["PANDDAStatus", "PanDDA\nStatus", "TEXT", 1], + ["DatePanDDAModelCreated", "DatePanDDAModelCreated", "TEXT", 0], + ["RefinementResolution", "Refinement\nResolution", "TEXT", 1], + ["RefinementResolutionTL", "RefinementResolutionTL", "TEXT", 0], + ["RefinementRcryst", "Refinement\nRcryst", "TEXT", 1], + ["RefinementRcrystTraficLight", "RefinementRcrystTraficLight", "TEXT", 0], + ["RefinementRfree", "Refinement\nRfree", "TEXT", 1], + ["RefinementRfreeTraficLight", "RefinementRfreeTraficLight", "TEXT", 0], + ["RefinementSpaceGroup", "Refinement\nSpace Group", "TEXT", 1], + ["RefinementLigandCC", "Ligand CC", "TEXT", 0], + ["RefinementRmsdBonds", "RefinementRmsdBonds", "TEXT", 1], + ["RefinementRmsdBondsTL", "RefinementRmsdBondsTL", "TEXT", 0], + ["RefinementRmsdAngles", "RefinementRmsdAngles", "TEXT", 1], + ["RefinementRmsdAnglesTL", "RefinementRmsdAnglesTL", "TEXT", 0], + ["RefinementOutcome", "Refinement\nOutcome", "TEXT", 1], + ["RefinementOutcomePerson", "RefinementOutcomePerson", "TEXT", 1], + ["RefinementOutcomeDate", "RefinementOutcomeDate", "TEXT", 1], + ["RefinementMTZfree", "RefinementMTZfree", "TEXT", 1], + ["RefinementTwinMTZfree", "RefinementTwinMTZfree", "TEXT", 1], + ["RefinementCIF", "RefinementCIF", "TEXT", 1], + ["RefinementCIFStatus", "Compound\nStatus", "TEXT", 1], + ["RefinementCIFprogram", "RefinementCIFprogram", "TEXT", 1], + ["RefinementPDB_latest", "RefinementPDB_latest", "TEXT", 1], + ["RefinementMTZ_latest", "RefinementMTZ_latest", "TEXT", 1], + ["RefinementMMCIFmodel_latest", "RefinementMMCIFmodel_latest", "TEXT", 1], + [ + "RefinementMMCIFreflections_latest", + "RefinementMMCIFreflections_latest", + "TEXT", + 1, + ], + ["RefinementMatrixWeight", "RefinementMatrixWeight", "TEXT", 0], + ["RefinementComment", "RefinementComment", "TEXT", 0], + [ + "RefinementPathToRefinementFolder", + "RefinementPathToRefinementFolder", + "TEXT", + 0, + ], + ["RefinementLigandConfidence", "Ligand\nConfidence", "TEXT", 0], + [ + "RefinementLigandBoundConformation", + "RefinementLigandBoundConformation", + "TEXT", + 0, + ], + ["RefinementBoundConformation", "RefinementBoundConformation", "TEXT", 0], + ["RefinementMolProbityScore", "MolProbity Score", "TEXT", 1], + ["RefinementMolProbityScoreTL", "RefinementMolProbityScoreTL", "TEXT", 0], + ["RefinementRamachandranOutliers", "Ramachandran\nOutliers", "TEXT", 1], + [ + "RefinementRamachandranOutliersTL", + "RefinementRamachandranOutliersTL", + "TEXT", + 0, + ], + ["RefinementRamachandranFavored", "Ramachandran\nFavored", "TEXT", 1], + [ + "RefinementRamachandranFavoredTL", + "RefinementRamachandranFavoredTL", + "TEXT", + 0, + ], + ["RefinementProgram", "RefinementProgram", "TEXT", 1], + ["RefinementStatus", "Refinement\nStatus", "TEXT", 1], + ["RefinementBusterReportHTML", "buster-reports", "TEXT", 1], + ["RefinementRefiner", "RefinementRefiner", "TEXT", 1], + ["RefinementDate", "RefinementDate", "TEXT", 1], + ["Deposition_PDB_ID", "Deposition_PDB_ID", "TEXT", 1], + ["Deposition_PDB_file", "Deposition_PDB_file", "TEXT", 0], + ["Deposition_Date", "Deposition_Date", "TEXT", 1], + ["Deposition_mmCIF_model_file", "Deposition_mmCIF_model_file", "TEXT", 0], + ["Deposition_mmCIF_SF_file", "Deposition_mmCIF_SF_file", "TEXT", 0], + ["Label", "Label", "TEXT", 0], + ["table_one", "table_one", "TEXT", 0], + ["AssayIC50", "AssayIC50", "TEXT", 0], + ["LastUpdated", "LastUpdated", "TEXT", 0], + ["LastUpdated_by", "LastUpdated_by", "TEXT", 0], + ] + + self.pandda_table_columns = [ + ["ID", "ID", "INTEGER PRIMARY KEY"], + ["CrystalName", "Sample ID", "TEXT"], + ["PANDDApath", "PANDDApath", "TEXT"], + ["PANDDA_site_index", "PANDDA_site_index", "TEXT"], + ["PANDDA_site_name", "PANDDA_site_name", "TEXT"], + ["PANDDA_site_comment", "PANDDA_site_comment", "TEXT"], + ["PANDDA_site_event_index", "PANDDA_site_event_index", "TEXT"], + ["PANDDA_site_event_comment", "PANDDA_site_event_comment", "TEXT"], + ["PANDDA_site_confidence", "PANDDA_site_confidence", "TEXT"], + ["PANDDA_site_InspectConfidence", "PANDDA_site_InspectConfidence", "TEXT"], + ["PANDDA_site_ligand_placed", "PANDDA_site_ligand_placed", "TEXT"], + ["PANDDA_site_viewed", "PANDDA_site_viewed", "TEXT"], + ["PANDDA_site_interesting", "PANDDA_site_interesting", "TEXT"], + ["PANDDA_site_z_peak", "PANDDA_site_z_peak", "TEXT"], + ["PANDDA_site_x", "PANDDA_site_x", "TEXT"], + ["PANDDA_site_y", "PANDDA_site_y", "TEXT"], + ["PANDDA_site_z", "PANDDA_site_z", "TEXT"], + ["PANDDA_site_ligand_id", "PANDDA_site_ligand_id", "TEXT"], + ["PANDDA_site_ligand_resname", "PANDDA_site_ligand_resname", "TEXT"], + ["PANDDA_site_ligand_chain", "PANDDA_site_ligand_chain", "TEXT"], + [ + "PANDDA_site_ligand_sequence_number", + "PANDDA_site_ligand_sequence_number", + "TEXT", + ], + ["PANDDA_site_ligand_altLoc", "PANDDA_site_ligand_altLoc", "TEXT"], + ["PANDDA_site_event_map", "PANDDA_site_event_map", "TEXT"], + ["PANDDA_site_event_map_mtz", "PANDDA_site_event_map_mtz", "TEXT"], + ["PANDDA_site_initial_model", "PANDDA_site_initial_model", "TEXT"], + ["PANDDA_site_initial_mtz", "PANDDA_site_initial_mtz", "TEXT"], + ["PANDDA_site_spider_plot", "PANDDA_site_spider_plot", "TEXT"], + ["PANDDA_site_occupancy", "PANDDA_site_occupancy", "TEXT"], + ["PANDDA_site_B_average", "PANDDA_site_B_average", "TEXT"], + [ + "PANDDA_site_B_ratio_residue_surroundings", + "PANDDA_site_B_ratio_residue_surroundings", + "TEXT", + ], + ["PANDDA_site_RSCC", "PANDDA_site_RSCC", "TEXT"], + ["PANDDA_site_RSR", "PANDDA_site_RSR", "TEXT"], + ["PANDDA_site_RSZD", "PANDDA_site_RSZD", "TEXT"], + ["PANDDA_site_rmsd", "PANDDA_site_rmsd", "TEXT"], + ["RefinementOutcome", "RefinementOutcome", "TEXT"], + ["ApoStructures", "ApoStructures", "TEXT"], + ["LastUpdated", "LastUpdated", "TEXT"], + ["LastUpdated_by", "LastUpdated_by", "TEXT"], + ] + + self.deposition_table_columns = [ + ["ID", "ID", "INTEGER PRIMARY KEY"], + ["CrystalName", "Sample ID", "TEXT"], + ["StructureType", "StructureType", "TEXT"], # apo/model + ["PDB_file", "PDB_file", "TEXT"], + ["MTZ_file", "MTZ_file", "TEXT"], + ["mmCIF_model_file", "mmCIF_model_file", "TEXT"], + ["mmCIF_SF_file", "mmCIF_SF_file", "TEXT"], + ["label", "label", "TEXT"], # for index.txt + ["description", "description", "TEXT"], # for index.txt + ["DimplePANDDApath", "DimplePANDDApath", "TEXT"], + ["contact_author_PI_salutation", "contact_author_PI_salutation", "TEXT"], + ["contact_author_PI_first_name", "contact_author_PI_first_name", "TEXT"], + ["contact_author_PI_last_name", "contact_author_PI_last_name", "TEXT"], + ["contact_author_PI_middle_name", "contact_author_PI_middle_name", "TEXT"], + ["contact_author_PI_role", "contact_author_PI_role", "TEXT"], + [ + "contact_author_PI_organization_type", + "contact_author_PI_organization_type", + "TEXT", + ], + [ + "contact_author_PI_organization_name", + "contact_author_PI_organization_name", + "TEXT", + ], + ["contact_author_PI_email", "contact_author_PI_email", "TEXT"], + ["contact_author_PI_address", "contact_author_PI_address", "TEXT"], + ["contact_author_PI_city", "contact_author_PI_city", "TEXT"], + [ + "contact_author_PI_State_or_Province", + "contact_author_PI_State_or_Province", + "TEXT", + ], + ["contact_author_PI_Zip_Code", "contact_author_PI_Zip_Code", "TEXT"], + ["contact_author_PI_Country", "contact_author_PI_Country", "TEXT"], + ["contact_author_PI_fax_number", "contact_author_PI_fax_number", "TEXT"], + [ + "contact_author_PI_phone_number", + "contact_author_PI_phone_number", + "TEXT", + ], + ["contact_author_PI_ORCID", "contact_author_PI_ORCID", "TEXT"], + ["contact_author_salutation", "contact_author_salutation", "TEXT"], + ["contact_author_first_name", "contact_author_first_name", "TEXT"], + ["contact_author_last_name", "contact_author_last_name", "TEXT"], + ["contact_author_middle_name", "contact_author_middle_name", "TEXT"], + ["contact_author_role", "contact_author_role", "TEXT"], + [ + "contact_author_organization_type", + "contact_author_organization_type", + "TEXT", + ], + [ + "contact_author_organization_name", + "contact_author_organization_name", + "TEXT", + ], + ["contact_author_email", "contact_author_email", "TEXT"], + ["contact_author_address", "contact_author_address", "TEXT"], + ["contact_author_city", "contact_author_city", "TEXT"], + [ + "contact_author_State_or_Province", + "contact_author_State_or_Province", + "TEXT", + ], + ["contact_author_Zip_Code", "contact_author_Zip_Code", "TEXT"], + ["contact_author_Country", "contact_author_Country", "TEXT"], + ["contact_author_fax_number", "contact_author_fax_number", "TEXT"], + ["contact_author_phone_number", "contact_author_phone_number", "TEXT"], + ["contact_author_ORCID", "contact_author_ORCID", "TEXT"], + [ + "Release_status_for_coordinates", + "Release_status_for_coordinates", + "TEXT", + ], + [ + "Release_status_for_structure_factor", + "Release_status_for_structure_factor", + "TEXT", + ], + ["Release_status_for_sequence", "Release_status_for_sequence", "TEXT"], + ["group_deposition_title", "group_deposition_title", "TEXT"], + ["group_description", "group_description", "TEXT"], + ["structure_title", "structure_title", "TEXT"], + ["structure_details", "structure_details", "TEXT"], + ["group_deposition_title_apo", "group_deposition_title_apo", "TEXT"], + ["structure_title_apo", "structure_title_apo", "TEXT"], + ["structure_author_name", "structure_author_name", "TEXT"], + ["primary_citation_author_name", "primary_citation_author_name", "TEXT"], + ["primary_citation_id", "primary_citation_id", "TEXT"], + [ + "primary_citation_journal_abbrev", + "primary_citation_journal_abbrev", + "TEXT", + ], + ["primary_citation_title", "primary_citation_title", "TEXT"], + ["primary_citation_year", "primary_citation_year", "TEXT"], + [ + "primary_citation_journal_volume", + "primary_citation_journal_volume", + "TEXT", + ], + ["primary_citation_page_first", "primary_citation_page_first", "TEXT"], + ["primary_citation_page_last", "primary_citation_page_last", "TEXT"], + ["molecule_name", "molecule_name", "TEXT"], + ["Fragment_name", "Fragment_name", "TEXT"], + ["Specific_mutation", "Specific_mutation", "TEXT"], + ["Enzyme_Comission_number", "Enzyme_Comission_number", "TEXT"], + [ + "Source_organism_scientific_name", + "Source_organism_scientific_name", + "TEXT", + ], + ["Source_organism_gene", "Source_organism_gene", "TEXT"], + ["Source_organism_strain", "Source_organism_strain", "TEXT"], + [ + "Expression_system_scientific_name", + "Expression_system_scientific_name", + "TEXT", + ], + ["Expression_system_strain", "Expression_system_strain", "TEXT"], + ["Expression_system_vector_type", "Expression_system_vector_type", "TEXT"], + [ + "Expression_system_plasmid_name", + "Expression_system_plasmid_name", + "TEXT", + ], + ["Manipulated_source_details", "Manipulated_source_details", "TEXT"], + [ + "fragment_name_one_specific_mutation", + "fragment_name_one_specific_mutation", + "TEXT", + ], + ["molecule_chain_one", "molecule_chain_one", "TEXT"], + ["molecule_name_two", "molecule_name_two", "TEXT"], + ["Fragment_name_two", "Fragment_name_two", "TEXT"], + ["Specific_mutation_two", "Specific_mutation_two", "TEXT"], + ["Enzyme_Comission_number_two", "Enzyme_Comission_number_two", "TEXT"], + [ + "Source_organism_scientific_name_two", + "Source_organism_scientific_name_two", + "TEXT", + ], + ["Source_organism_gene_two", "Source_organism_gene_two", "TEXT"], + ["Source_organism_strain_two", "Source_organism_strain_two", "TEXT"], + [ + "Expression_system_scientific_name_two", + "Expression_system_scientific_name_two", + "TEXT", + ], + ["Expression_system_strain_two", "Expression_system_strain_two", "TEXT"], + [ + "Expression_system_vector_type_two", + "Expression_system_vector_type_two", + "TEXT", + ], + [ + "Expression_system_plasmid_name_two", + "Expression_system_plasmid_name_two", + "TEXT", + ], + [ + "Manipulated_source_details_two", + "Manipulated_source_details_two", + "TEXT", + ], + [ + "fragment_name_two_specific_mutation", + "fragment_name_one_specific_mutation_two", + "TEXT", + ], + ["molecule_chain_two", "molecule_chain_two", "TEXT"], + ["structure_keywords", "structure_keywords", "TEXT"], + [ + "biological_assembly_chain_number", + "biological_assembly_chain_number", + "TEXT", + ], + ["crystallization_id", "crystallization_id", "TEXT"], + ["crystallization_method", "crystallization_method", "TEXT"], + ["crystallization_pH", "crystallization_pH", "TEXT"], + ["crystallization_temperature", "crystallization_temperature", "TEXT"], + ["crystallization_details", "crystallization_details", "TEXT"], + ["radiation_source", "radiation_source", "TEXT"], + ["radiation_source_type", "radiation_source_type", "TEXT"], + ["radiation_wavelengths", "radiation_wavelengths", "TEXT"], + ["radiation_detector", "radiation_detector", "TEXT"], + ["radiation_detector_type", "radiation_detector_type", "TEXT"], + ["data_collection_date", "data_collection_date", "TEXT"], + ["data_collection_temperature", "data_collection_temperature", "TEXT"], + ["data_collection_protocol", "data_collection_protocol", "TEXT"], + ["SG_project_name", "SG_project_name", "TEXT"], + ["full_name_of_SG_center", "full_name_of_SG_center", "TEXT"], + ["molecule_one_letter_sequence", "molecule_one_letter_sequence", "TEXT"], + [ + "molecule_one_letter_sequence_uniprot_id", + "molecule_one_letter_sequence_uniprot_id", + "TEXT", + ], + ["molecule_two_letter_sequence", "molecule_two_letter_sequence", "TEXT"], + [ + "molecule_two_letter_sequence_uniprot_id", + "molecule_two_letter_sequence_uniprot_id", + "TEXT", + ], + ["CrystalName_of_pandda_input", "CrystalName_of_pandda_input", "TEXT"], + ["pdbx_starting_model", "pdbx_starting_model", "TEXT"], + ["data_integration_software", "data_integration_software", "TEXT"], + ["phasing_software", "phasing_software", "TEXT"], + ["pdbx_funding_ordinal_one", "pdbx_funding_ordinal_one", "TEXT"], + ["pdbx_funding_organization_one", "pdbx_funding_organization_one", "TEXT"], + ["pdbx_grant_number_one", "pdbx_grant_number_one", "TEXT"], + ["pdbx_grant_country_one", "pdbx_grant_country_one", "TEXT"], + ["pdbx_funding_ordinal_two", "pdbx_funding_ordinal_two", "TEXT"], + ["pdbx_funding_organization_two", "pdbx_funding_organization_two", "TEXT"], + ["pdbx_grant_number_two", "pdbx_grant_number_two", "TEXT"], + ["pdbx_grant_country_two", "pdbx_grant_country_two", "TEXT"], + ["pdbx_funding_ordinal_three", "pdbx_funding_ordinal_three", "TEXT"], + [ + "pdbx_funding_organization_three", + "pdbx_funding_organization_three", + "TEXT", + ], + ["pdbx_grant_number_three", "pdbx_grant_number_three", "TEXT"], + ["pdbx_grant_country_three", "pdbx_grant_country_three", "TEXT"], + ["LastUpdated", "LastUpdated", "TEXT"], + ["LastUpdated_by", "LastUpdated_by", "TEXT"], + ] + + self.data_collection_columns = [ + ["ID", "ID", "INTEGER PRIMARY KEY"], + ["CrystalName", "Sample ID", "TEXT", 0], + ["ProteinName", "ProteinName", "TEXT", 1], + ["DataCollectionVisit", "Visit", "TEXT", 0], + ["DataCollectionRun", "Run", "TEXT", 0], + ["DataCollectionSubdir", "SubDir", "TEXT", 0], + ["DataCollectionBeamline", "Beamline", "TEXT", 0], + ["DataCollectionOutcome", "DataCollection\nOutcome", "TEXT", 1], + ["DataCollectionDate", "Data Collection\nDate", "TEXT", 1], + ["DataCollectionWavelength", "Wavelength", "TEXT", 0], + ["DataCollectionPinBarcode", "GDA\nBarcode", "TEXT", 1], + ["DataCollectionCrystalImage1", "img1", "TEXT", 1], + ["DataCollectionCrystalImage2", "img2", "TEXT", 1], + ["DataCollectionCrystalImage3", "img3", "TEXT", 1], + ["DataCollectionCrystalImage4", "img4", "TEXT", 1], + [ + "DataProcessingPathToImageFiles", + "Path to diffraction\nimage files", + "TEXT", + 1, + ], + ["DataProcessingProgram", "Program", "TEXT", 1], + ["DataProcessingSpaceGroup", "DataProcessing\nSpaceGroup", "TEXT", 1], + ["DataProcessingUnitCell", "DataProcessing\nUnitCell", "TEXT", 0], + ["DataProcessingAutoAssigned", "auto-assigned", "TEXT", 0], + ["DataProcessingA", "DataProcessing\nA", "TEXT", 0], + ["DataProcessingB", "DataProcessing\nB", "TEXT", 0], + ["DataProcessingC", "DataProcessing\nC", "TEXT", 0], + ["DataProcessingAlpha", "DataProcessing\nAlpha", "TEXT", 0], + ["DataProcessingBeta", "DataProcessing\nBeta", "TEXT", 0], + ["DataProcessingGamma", "DataProcessing\nGamma", "TEXT", 0], + ["DataProcessingResolutionOverall", "Resolution\nOverall", "TEXT", 0], + ["DataProcessingResolutionLow", "Resolution\nLow", "TEXT", 0], + [ + "DataProcessingResolutionLowInnerShell", + "Resolution\nLow (Inner Shell)", + "TEXT", + 0, + ], + ["DataProcessingResolutionHigh", "Resolution\nHigh", "TEXT", 1], + [ + "DataProcessingResolutionHigh15sigma", + "Resolution\n[Mn = 1.5]", + "TEXT", + 1, + ], + [ + "DataProcessingResolutionHigh20sigma", + "Resolution\n[Mn = 2.0]", + "TEXT", + 1, + ], + [ + "DataProcessingResolutionHighOuterShell", + "Resolution\nHigh (Outer Shell)", + "TEXT", + 0, + ], + ["DataProcessingRmergeOverall", "Rmerge\nOverall", "TEXT", 1], + ["DataProcessingRmergeLow", "Rmerge\nLow", "TEXT", 1], + ["DataProcessingRmergeHigh", "Rmerge\nHigh", "TEXT", 1], + ["DataProcessingIsigOverall", "Mn\nOverall", "TEXT", 1], + ["DataProcessingIsigLow", "Mn\nLow", "TEXT", 1], + ["DataProcessingIsigHigh", "Mn\nHigh", "TEXT", 1], + ["DataProcessingCompletenessOverall", "Completeness\nOverall", "TEXT", 1], + ["DataProcessingCompletenessLow", "Completeness\nLow", "TEXT", 1], + ["DataProcessingCompletenessHigh", "Completeness\nHigh", "TEXT", 1], + ["DataProcessingMultiplicityOverall", "Multiplicity\nOverall", "TEXT", 1], + ["DataProcessingMultiplicityLow", "Multiplicity\nLow", "TEXT", 1], + ["DataProcessingMultiplicityHigh", "Multiplicity\nHigh", "TEXT", 1], + ["DataProcessingCChalfOverall", "CC(1/2)\nOverall", "TEXT", 1], + ["DataProcessingCChalfLow", "CC(1/2)\nLow", "TEXT", 1], + ["DataProcessingCChalfHigh", "CC(1/2)\nHigh", "TEXT", 1], + ["DataProcessingPathToLogfile", "DataProcessingPathToLogfile", "TEXT", 1], + ["DataProcessingPathToMTZfile", "DataProcessingPathToMTZfile", "TEXT", 1], + ["DataProcessingLOGfileName", "DataProcessingLOGfileName", "TEXT", 0], + ["DataProcessingMTZfileName", "DataProcessingMTZfileName", "TEXT", 0], + [ + "DataProcessingDirectoryOriginal", + "DataProcessingDirectoryOriginal", + "TEXT", + 0, + ], + [ + "DataProcessingUniqueReflectionsOverall", + "Unique Reflections\nOverall", + "TEXT", + 1, + ], + [ + "DataProcessingUniqueReflectionsLow", + "Unique Reflections\nlow", + "TEXT", + 1, + ], + [ + "DataProcessingUniqueReflectionsHigh", + "Unique Reflections\nhigh", + "TEXT", + 1, + ], + ["DataProcessingLattice", "DataProcessing\nLattice", "TEXT", 0], + ["DataProcessingPointGroup", "DataProcessing\nPointGroup", "TEXT", 0], + [ + "DataProcessingUnitCellVolume", + "DataProcessing\nUnit Cell Volume", + "TEXT", + 0, + ], + ["DataProcessingAlert", "DataProcessing\nAlert", "TEXT", 0], + ["DataProcessingScore", "DataProcessing\nScore", "TEXT", 1], + ["DataProcessingStatus", "DataProcessing\nStatus", "TEXT", 1], + ["LastUpdated", "LastUpdated", "TEXT", 0], + ["LastUpdated_by", "LastUpdated_by", "TEXT", 0], + ] + + self.zenodo_table_columns = [ + ["ID", "ID", "INTEGER PRIMARY KEY"], + ["DimplePANDDApath", "DimplePANDDApath", "TEXT"], + ["ZenodoTitle", "ZenodoTitle", "TEXT"], + ["ZenodoHTTPS", "ZenodoHTTPS", "TEXT"], + ["ZenodoDOI", "ZenodoDOI", "TEXT"], + ["LastUpdated", "LastUpdated", "TEXT"], + ["LastUpdated_by", "LastUpdated_by", "TEXT"], + ] + + self.label_table_columns = [ + ["ID", "ID", "INTEGER PRIMARY KEY"], + ["Label", "Label", "TEXT"], + ["Description", "Description", "TEXT"], + ] + + def columns_not_to_display(self): + do_not_display = [] + for column in self.column_list: + if column[3] == 0: + do_not_display.append(column[1]) + return do_not_display + + def create_missing_columns(self): + existing_columns = [] + connect = sqlite3.connect(self.data_source_file) + connect.row_factory = sqlite3.Row + cursor = connect.cursor() + + tableDict = { + "mainTable": self.column_list, + "panddaTable": self.pandda_table_columns, + "depositTable": self.deposition_table_columns, + "collectionTable": self.data_collection_columns, + "zenodoTable": self.zenodo_table_columns, + "labelTable": self.label_table_columns, + } + + for table in tableDict: + cursor.execute("create table if not exists " + table + " (ID INTEGER);") + existing_columns = [] + cursor.execute("SELECT * FROM " + table) + for column in cursor.description: + existing_columns.append(column[0]) + for column in tableDict[table]: + if column[0] not in existing_columns: + cursor.execute( + "alter table " + + table + + " add column '" + + column[0] + + "' '" + + column[2] + + "'" + ) + connect.commit() + if table == "labelTable": + cursor.execute("select ID from labelTable") + id = cursor.fetchall() + if id == []: + for idx in range(5): + cursor.execute( + "insert into labelTable (ID) Values (%s)" % str(idx + 1) + ) + + def return_column_list(self): + return self.column_list + + def create_empty_data_source_file(self): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + with connect: + cursor = connect.cursor() + cursor.execute( + "CREATE TABLE mainTable(" + + self.column_list[0][0] + + " " + + self.column_list[0][2] + + ")" + ) + for i in range(1, len(self.column_list)): + cursor.execute( + "alter table mainTable add column '" + + self.column_list[i][0] + + "' '" + + self.column_list[i][2] + + "'" + ) + connect.commit() + # Don't need to create panddaTable at this point, because table will be created + # by create_missing_columns which is called the first time a data source in + # specified in XCE + + def get_all_samples_in_data_source_as_list(self): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute("SELECT CrystalName FROM mainTable") + existing_samples_in_db = [] + samples = cursor.fetchall() + for sample in samples: + existing_samples_in_db.append(str(sample[0])) + return existing_samples_in_db + + def execute_statement(self, cmd): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute(cmd) + output = cursor.fetchall() + connect.commit() + return output + + def get_db_dict_for_sample(self, sampleID): + db_dict = {} + header = [] + data = [] + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute( + "select * from mainTable where CrystalName='{0!s}';".format(sampleID) + ) + print( + ( + "SQLITE: select * from mainTable where CrystalName='{0!s}';".format( + sampleID + ) + ) + ) + for column in cursor.description: + header.append(column[0]) + data = cursor.fetchall() + print(("DATA: {0!s}".format(data))) + for n, item in enumerate(data[0]): + db_dict[header[n]] = str(item) + return db_dict + + def get_deposit_dict_for_sample(self, sampleID): + db_dict = {} + header = [] + data = [] + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute( + "select * from depositTable where CrystalName='{0!s}';".format(sampleID) + ) + for column in cursor.description: + header.append(column[0]) + data = cursor.fetchall() + try: + for n, item in enumerate(data[0]): + db_dict[header[n]] = str(item) + except IndexError: + pass + return db_dict + + def get_db_pandda_dict_for_sample_and_site_and_event( + self, sampleID, site_index, event_index + ): + db_dict = {} + header = [] + data = [] + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute( + "select * from panddaTable where CrystalName='{0!s}'" + " and PANDDA_site_index='{1!s}'" + " and PANDDA_site_event_index='{2!s}'" + " and PANDDA_site_ligand_placed='True';".format( + sampleID, site_index, event_index + ) + ) + for column in cursor.description: + header.append(column[0]) + data = cursor.fetchall() + for n, item in enumerate(data[0]): + db_dict[header[n]] = str(item) + return db_dict + + def check_if_sample_exists_in_data_source(self, sampleID): + sample_exists = False + existing_samples_in_db = self.get_all_samples_in_data_source_as_list() + if sampleID in existing_samples_in_db: + sample_exists = True + return sample_exists + + def import_csv_file(self, csv_file): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + available_columns = [] + cursor.execute("SELECT * FROM mainTable") + for column in cursor.description: # only update existing columns in data source + available_columns.append(column[0]) + with open(csv_file, "rb") as csv_import: # `with` statement available in 2.5+ + # csv.DictReader uses first line in file for column headings by default + csv_dict = csv.DictReader(csv_import) # comma is default delimiter + for line in csv_dict: + sampleID = line["CrystalName"] + if str(sampleID).replace(" ", "") == "": + continue + if self.check_if_sample_exists_in_data_source(sampleID): + update_string = "" + for key, value in line.items(): + if key == "ID" or key == "CrystalName": + continue + if key not in available_columns: + continue + # this is how I had it originally, so it would ignore empty + # fields. the problem is that if the user wants to set all + # values to Null. if will ignore it and leave the inital value + # in the datasource. now try this instead; not sure what will + # break now... + update_string += str(key) + "=" + "'" + str(value) + "'" + "," + cursor.execute( + "UPDATE mainTable SET " + + update_string[:-1] + + " WHERE CrystalName=" + + "'" + + sampleID + + "';" + ) + else: + column_string = "" + value_string = "" + for key, value in line.items(): + if key == "ID": + continue + if key not in available_columns: + continue + # ignore if nothing in csv field + if not str(value).replace(" ", "") == "": + value_string += "'" + value + "'" + "," + column_string += key + "," + cursor.execute( + "INSERT INTO mainTable (" + + column_string[:-1] + + ") VALUES (" + + value_string[:-1] + + ");" + ) + + connect.commit() + + def update_data_source(self, sampleID, data_dict): + print("here") + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + + # need to do this since some older sqlite files contain a columnn called + # DataProcessingResolutionHigh1.5sigma + # and this does not go down well with the SQLite statement below + removeKey = "" + for key in data_dict: + if ".5" in key: + removeKey = key + break + if removeKey != "": + del data_dict[removeKey] + + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + update_string = "" + for key in data_dict: + value = data_dict[key] + if key == "ID" or key == "CrystalName": + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string += str(key) + "=" + "'" + str(value) + "'" + "," + else: + update_string += str(key) + " = null," + if update_string != "": + cursor.execute( + "UPDATE mainTable SET " + + update_string[:-1] + + " WHERE CrystalName=" + + "'" + + sampleID + + "'" + ) + connect.commit() + + def update_panddaTable(self, sampleID, site_index, data_dict): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + update_string = "" + for key in data_dict: + value = data_dict[key] + if key == "ID" or key == "CrystalName" or key == "PANDDA_site_index": + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string += str(key) + "=" + "'" + str(value) + "'" + "," + else: + update_string += str(key) + " = null," + if update_string != "": + cursor.execute( + "UPDATE panddaTable SET " + + update_string[:-1] + + " WHERE CrystalName='{0!s}' and PANDDA_site_index='{1!s}'".format( + sampleID, site_index + ) + ) + connect.commit() + + def update_site_event_panddaTable( + self, sampleID, site_index, event_index, data_dict + ): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + update_string = "" + for key in data_dict: + value = data_dict[key] + if ( + key == "ID" + or key == "CrystalName" + or key == "PANDDA_site_index" + or key == "PANDDA_site_event_index" + ): + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string += str(key) + "=" + "'" + str(value) + "'" + "," + else: + update_string += str(key) + " = null," + if update_string != "": + cursor.execute( + "UPDATE panddaTable SET " + + update_string[:-1] + + " WHERE CrystalName='{0!s}' and PANDDA_site_index='{1!s}'" + " and PANDDA_site_event_index='{2!s}'".format( + sampleID, site_index, event_index + ) + ) + connect.commit() + + def update_depositTable(self, sampleID, structure_type, data_dict): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + update_string = "" + for key in data_dict: + value = data_dict[key] + if key == "ID" or key == "CrystalName" or key == "StructureType": + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string += ( + str(key) + + "=" + + '"' + + str(value).replace("\r", "").replace("\n", "") + + '"' + + "," + ) + else: + update_string += str(key) + " = null," + if update_string != "": + cursor.execute( + "UPDATE depositTable SET " + + update_string[:-1] + + ' WHERE CrystalName="{0!s}" and StructureType="{1!s}"'.format( + sampleID, structure_type + ) + ) + connect.commit() + + def update_specified_table(self, sampleID, data_dict, table): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + update_string = "" + for key in data_dict: + value = data_dict[key] + if key == "ID" or key == "CrystalName": + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string += str(key) + "=" + "'" + str(value) + "'" + "," + if update_string != "": + cursor.execute( + "UPDATE " + + table + + " SET " + + update_string[:-1] + + " WHERE CrystalName=" + + "'" + + sampleID + + "'" + ) + connect.commit() + + def update_insert_data_source(self, sampleID, data_dict): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute("Select CrystalName FROM mainTable") + available_columns = [] + cursor.execute("SELECT * FROM mainTable") + for column in cursor.description: # only update existing columns in data source + available_columns.append(column[0]) + if self.check_if_sample_exists_in_data_source(sampleID): + for key in data_dict: + value = data_dict[key] + if key == "ID" or key == "CrystalName": + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string = str(key) + "=" + "'" + str(value) + "'" + cursor.execute( + "UPDATE mainTable SET " + + update_string + + " WHERE CrystalName=" + + "'" + + sampleID + + "';" + ) + else: + column_string = "CrystalName" + "," + value_string = "'" + sampleID + "'" + "," + for key in data_dict: + value = data_dict[key] + if key == "ID": + continue + if key not in available_columns: + continue + if ( + not str(value).replace(" ", "") == "" + ): # ignore if nothing in csv field + value_string += "'" + str(value) + "'" + "," + column_string += key + "," + cursor.execute( + "INSERT INTO mainTable (" + + column_string[:-1] + + ") VALUES (" + + value_string[:-1] + + ");" + ) + connect.commit() + + def update_insert_any_table(self, table, data_dict, condition_dict): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + + # columns + columns = "" + for c in condition_dict: + columns += c + "," + + # condition + condition_string = "" + for key in condition_dict: + condition = condition_dict[key] + condition_string += str(key) + "=" + "'" + str(condition) + "' and " + + cursor.execute( + "Select %s FROM %s where %s" % (columns[:-1], table, condition_string[:-5]) + ) + + tmp = cursor.fetchall() + if not tmp: + data_dict.update(condition_dict) + value_string = "" + column_string = "" + for key in data_dict: + value = data_dict[key] + value_string += "'" + str(value) + "'" + "," + column_string += key + "," + cursor.execute( + "INSERT INTO " + + table + + " (" + + column_string[:-1] + + ") VALUES (" + + value_string[:-1] + + ");" + ) + else: + update_string = "" + for key in data_dict: + value = data_dict[key] + update_string += str(key) + "=" + "'" + str(value) + "'," + cursor.execute( + "UPDATE " + + table + + " SET " + + update_string[:-1] + + " WHERE " + + condition_string[:-5] + + ";" + ) + connect.commit() + + def update_insert_site_event_panddaTable(self, sampleID, data_dict): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute( + "Select CrystalName,PANDDA_site_index,PANDDA_site_event_index" + " FROM panddaTable" + ) + samples_sites_in_table = [] + tmp = cursor.fetchall() + for item in tmp: + line = [x.encode("UTF8") for x in list(item)] + samples_sites_in_table.append(line) + + found_sample_site = False + for entry in samples_sites_in_table: + if ( + entry[0] == sampleID + and entry[1] == data_dict["PANDDA_site_index"] + and entry[2] == data_dict["PANDDA_site_event_index"] + ): + found_sample_site = True + + if found_sample_site: + for key in data_dict: + value = data_dict[key] + if ( + key == "ID" + or key == "CrystalName" + or key == "PANDDA_site_index" + or key == "PANDDA_site_event_index" + ): + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string = str(key) + "=" + "'" + str(value) + "'" + cursor.execute( + "UPDATE panddaTable SET " + + update_string + + " WHERE CrystalName=" + + "'" + + sampleID + + "' and PANDDA_site_index is '" + + data_dict["PANDDA_site_index"] + + "' and PANDDA_site_event_index is '" + + data_dict["PANDDA_site_event_index"] + + "';" + ) + else: + column_string = "" + value_string = "" + for key in data_dict: + value = data_dict[key] + if key == "ID": + continue + if ( + not str(value).replace(" ", "") == "" + ): # ignore if nothing in csv field + value_string += "'" + str(value) + "'" + "," + column_string += key + "," + print( + "INSERT INTO panddaTable (" + + column_string[:-1] + + ") VALUES (" + + value_string[:-1] + + ");" + ) + cursor.execute( + "INSERT INTO panddaTable (" + + column_string[:-1] + + ") VALUES (" + + value_string[:-1] + + ");" + ) + connect.commit() + + def update_insert_depositTable(self, sampleID, data_dict): + data_dict["LastUpdated"] = str(datetime.now().strftime("%Y-%m-%d %H:%M")) + data_dict["LastUpdated_by"] = getpass.getuser() + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + available_columns = [] + cursor.execute("SELECT * FROM depositTable") + for column in cursor.description: # only update existing columns in data source + available_columns.append(column[0]) + + cursor.execute("Select CrystalName FROM depositTable") + samples_in_table = [] + tmp = cursor.fetchall() + for item in tmp: + line = [x.encode("UTF8") for x in list(item)] + if str(item) not in samples_in_table: + samples_in_table.append(str(line[0])) + + if sampleID in samples_in_table: + for key in data_dict: + value = data_dict[key] + if key == "ID" or key == "CrystalName": + continue + if not str(value).replace(" ", "") == "": # ignore empty fields + update_string = str(key) + "=" + "'" + str(value) + "'" + print( + "UPDATE depositTable SET " + + update_string + + " WHERE CrystalName=" + + "'" + + sampleID + + "';" + ) + cursor.execute( + "UPDATE depositTable SET " + + update_string + + " WHERE CrystalName=" + + "'" + + sampleID + + "';" + ) + else: + column_string = "CrystalName" + "," + value_string = "'" + sampleID + "'" + "," + for key in data_dict: + value = data_dict[key] + if key == "ID": + continue + if key not in available_columns: + continue + if ( + not str(value).replace(" ", "") == "" + ): # ignore if nothing in csv field + value_string += "'" + str(value) + "'" + "," + column_string += key + "," + print( + "INSERT INTO depositTable (" + + column_string[:-1] + + ") VALUES (" + + value_string[:-1] + + ");" + ) + cursor.execute( + "INSERT INTO depositTable (" + + column_string[:-1] + + ") VALUES (" + + value_string[:-1] + + ");" + ) + connect.commit() + + def export_to_csv_file(self, csv_file): + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute("SELECT * FROM mainTable") + header = () + for column in cursor.description: + header += (column[0],) + rows = cursor.fetchall() + csvWriter = csv.writer(open(csv_file, "w")) + csvWriter.writerows([header] + rows) + + def load_samples_from_data_source(self): + header = [] + data = [] + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute("SELECT * FROM mainTable") + for column in cursor.description: + header.append(column[0]) + data = cursor.fetchall() + return header, data + + def get_todoList_for_coot(self, RefinementOutcome): + sample_list_for_coot = [] + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + + if RefinementOutcome == "0 - All Datasets": + outcome = " not null " + else: + outcome = " '{0!s}' ".format(RefinementOutcome) + + sqlite = ( + "select" + " CrystalName," + " CompoundCode," + " RefinementCIF," + " RefinementMTZfree," + " RefinementPathToRefinementFolder," + " RefinementOutcome," + " RefinementLigandConfidence " + "from mainTable " + "where RefinementOutcome is %s" + " and (DimpleRfree is not Null or RefinementRfree is not Null)" + " order by CrystalName ASC;" % outcome + ) + + cursor.execute(sqlite) + + tmp = cursor.fetchall() + for item in tmp: + tmpx = [] + for i in list(item): + if i is None: + tmpx.append("None") + else: + tmpx.append(i) + line = [x.encode("UTF8") for x in tmpx] + sample_list_for_coot.append(line) + + crystalDict = {} + for entry in sample_list_for_coot: + if entry[0] not in crystalDict: + sqlite = ( + "select" + " PANDDA_site_event_map," + " PANDDA_site_x," + " PANDDA_site_y," + " PANDDA_site_z," + " PANDDA_site_spider_plot," + " PANDDA_site_index," + " PANDDA_site_event_index," + " PANDDA_site_confidence," + " PANDDA_site_name," + " PANDDA_site_InspectConfidence," + " PANDDA_site_interesting," + " PANDDA_site_event_comment " + "from panddaTable " + "where " + " CrystalName is '%s';" % entry[0] + ) + cursor.execute(sqlite) + tmp = cursor.fetchall() + if tmp: + crystalDict[entry[0]] = [] + for item in tmp: + print( + [ + entry[0], + str(item[0]), + str(item[1]), + str(item[2]), + str(item[3]), + str(item[4]), + str(item[5]), + str(item[6]), + str(item[7]), + str(item[8]), + str(item[9]), + str(item[10]), + str(item[11]), + ] + ) + crystalDict[entry[0]].append( + [ + str(item[0]), + str(item[1]), + str(item[2]), + str(item[3]), + str(item[4]), + str(item[5]), + str(item[6]), + str(item[7]), + str(item[8]), + str(item[9]), + str(item[10]), + str(item[11]), + ] + ) + + return sample_list_for_coot, crystalDict + + def translate_xce_column_list_to_sqlite(self, column_list): + out_list = [] + for item in column_list: + if item.startswith("Exclude"): + out_list.append(["Exclude"]) + if item.startswith("Ignore"): + out_list.append(["Ignore"]) + if item.startswith("Export"): + out_list.append(["Export", item]) + continue + if item.startswith("Show"): + out_list.append([item, item]) + continue + if item.startswith("Run\nDimple"): + out_list.append([item, item]) + continue + if item.startswith("Select"): + out_list.append([item, item]) + continue + if item.startswith("Run\nxia2"): + out_list.append([item, item]) + continue + if item.startswith("Dataset ID"): + out_list.append([item, item]) + continue + if item.startswith("Reference\nSpaceGroup"): + out_list.append([item, item]) + continue + if item.startswith("Difference\nUC Volume (%)"): + out_list.append([item, item]) + continue + if item.startswith("Reference File"): + out_list.append([item, item]) + continue + if item.startswith("PanDDA site details"): + out_list.append([item, item]) + continue + for entry in self.column_list: + if entry[1] == item: + out_list.append([item, entry[0]]) + break + return out_list + + def export_csv_for_WONKA(self): + SQLite = ( + "select" + " panddaTable.PANDDA_site_ligand_resname," + " panddaTable.PANDDA_site_ligand_sequence_number," + " panddaTable.PANDDA_site_ligand_chain," + " panddaTable.RefinementOutcome," + " mainTable.CompoundSMILES," + " mainTable.RefinementBoundConformation," + " panddaTable.PANDDA_site_initial_mtz," + " panddaTable.PANDDA_site_event_map," + " panddaTable.CrystalName," + " mainTable.CompoundCode " + "from" + " mainTable inner join panddaTable" + " on mainTable.CrystalName = panddaTable.CrystalName " + "where (panddaTable.RefinementOutcome like '3%'" + " or panddaTable.RefinementOutcome like '4%'" + " or panddaTable.RefinementOutcome like '5%')" + ) + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute(SQLite) + header = () + for column in cursor.description: + header += (column[0],) + rows = cursor.fetchall() + csvWriter = csv.writer(open("for_wonka.csv", "w")) + csvWriter.writerows([header] + rows) + + def create_or_remove_missing_records_in_depositTable( + self, xce_logfile, xtal, type, db_dict + ): + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + Logfile = XChemLog.updateLog(xce_logfile) + oldRefiStage = "" + if type == "ligand_bound": + cursor.execute( + "select RefinementOutcome" + " from mainTable where CrystalName is '{0!s}'".format(xtal) + ) + tmp = cursor.fetchall() + oldRefiStage = str(tmp[0][0]) + Logfile.insert( + 'setting RefinementOutcome field to "' + + db_dict["RefinementOutcome"] + + '" for ' + + xtal + ) + self.update_insert_data_source(xtal, db_dict) + elif type == "ground_state": + cursor.execute( + "select DimplePANDDApath from depositTable" + " where StructureType is '{0!s}'" + " and DimplePANDDApath is '{1!s}'".format( + type, db_dict["DimplePANDDApath"] + ) + ) + tmp = cursor.fetchall() + if not tmp: + Logfile.insert( + "entry for ground-state model in depositTable does not exist" + ) + else: + Logfile.warning( + "entry for ground-state model in depositTable does already exist" + ) + Logfile.warning( + "updating PDB, MTZ and DimplePANDDApath for ground-state entry" + ) + cursor.execute( + "update depositTable set PDB_file='%s', MTZ_file='%s'," + " DimplePANDDApath='%s' where StructureType='ground_state'" + % ( + db_dict["PDB_file"], + db_dict["MTZ_file"], + db_dict["DimplePANDDApath"], + ) + ) + connect.commit() + return + + cursor.execute( + "select CrystalName,StructureType from depositTable" + " where CrystalName is '{0!s}' and StructureType is '{1!s}'".format( + xtal, type + ) + ) + tmp = cursor.fetchall() + if type == "ligand_bound": + if not tmp and int(db_dict["RefinementOutcome"].split()[0]) == 5: + sqlite = ( + "insert into depositTable (CrystalName,StructureType)" + " values ('{0!s}','{1!s}');".format(xtal, type) + ) + Logfile.insert( + "creating new entry for " + + str(type) + + " structure of " + + xtal + + " in depositTable" + ) + cursor.execute(sqlite) + connect.commit() + else: + if int(db_dict["RefinementOutcome"].split()[0]) != 5: + sqlite = ( + "delete from depositTable where CrystalName is '{0!s}'" + " and StructureType is '{1!s}'".format(xtal, type) + ) + if oldRefiStage.startswith("5"): + Logfile.insert( + "removing entry for " + + str(type) + + " structure of " + + xtal + + " from depositTable" + ) + cursor.execute(sqlite) + connect.commit() + elif type == "ground_state": + sqlite = ( + "insert into depositTable" + " (CrystalName,StructureType,DimplePANDDApath,PDB_file,MTZ_file)" + " values ('{0!s}','{1!s}','{2!s}','{3!s}','{4!s}');".format( + xtal, + type, + db_dict["DimplePANDDApath"], + db_dict["PDB_file"], + db_dict["MTZ_file"], + ) + ) + Logfile.insert( + "creating new entry for " + + str(type) + + " structure of " + + xtal + + " in depositTable" + ) + cursor.execute(sqlite) + connect.commit() + + def collected_xtals_during_visit(self, visitID): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute( + "select CrystalName from collectionTable" + " where DataCollectionVisit = '{0!s}'".format(visitID) + ) + collectedXtals = [] + samples = cursor.fetchall() + for sample in samples: + if str(sample[0]) not in collectedXtals: + collectedXtals.append(str(sample[0])) + return collectedXtals + + def collected_xtals_during_visit_for_scoring(self, visit): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + xtalList = [] + cursor.execute( + "select distinct CrystalName from collectionTable" + " where DataCollectionVisit = '%s'" % visit + ) + samples = cursor.fetchall() + for sample in samples: + if str(sample[0]) not in xtalList: + xtalList.append(str(sample[0])) + return xtalList + + def autoprocessing_result_user_assigned(self, sample): + userassigned = False + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute( + "select DataProcessingAutoAssigned from mainTable where CrystalName = '%s'" + % sample + ) + outcome = cursor.fetchall() + try: + if ( + "false" in str(outcome[0]).lower() + or str(outcome[0]).encode("ascii", "ignore") == "" + ): + userassigned = ( + True # a bit counterintuitive, but here we ask about userassigned + ) + # whereas DB records autoassigned + except IndexError: + pass # this is the case when sample is encountered the first time + # and not yet in mainTable + + return userassigned + + def all_autoprocessing_results_for_xtal_as_dict(self, xtal): + dbList = [] + header = [] + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute( + "select * from collectionTable where CrystalName='{0!s}';".format(xtal) + ) + for column in cursor.description: + header.append(column[0]) + data = cursor.fetchall() + for result in data: + db_dict = {} + for n, item in enumerate(result): + db_dict[header[n]] = str(item) + dbList.append(db_dict) + return dbList + + def get_db_dict_for_visit_run_autoproc_score( + self, xtal, visit, run, autoproc, score + ): + db_dict = {} + header = [] + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + sqlite = ( + "select * " + "from collectionTable " + "where CrystalName ='%s' and" % xtal + + " DataCollectionVisit = '%s' and" % visit + + " DataCollectionRun = '%s' and" % run + + " DataProcessingProgram = '%s' and" % autoproc + + " DataProcessingScore = '%s'" % score + ) + cursor.execute(sqlite) + for column in cursor.description: + header.append(column[0]) + data = cursor.fetchall() + print(("SQLITE: {0!s}".format(sqlite))) + print(("DATA: {0!s}".format(data))) + for n, item in enumerate(data[0]): + db_dict[header[n]] = str(item) + return db_dict + + def xtals_collected_during_visit_as_dict(self, visitID): + # first get all collected xtals as list + if isinstance(visitID, list): # for Agamemnon data structure + collectedXtals = [] + for visit in visitID: + x = self.collected_xtals_during_visit(visit) + for e in x: + collectedXtals.append(e) + else: + collectedXtals = self.collected_xtals_during_visit(visitID) + xtalDict = {} + # creates sqlite file if non existent + sqlite3.connect(self.data_source_file).cursor() + for xtal in sorted(collectedXtals): + db_dict = self.get_db_dict_for_sample(xtal) + xtalDict[xtal] = db_dict + return xtalDict + + def samples_for_html_summary(self, whichSamples): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + if whichSamples.startswith("4"): + cursor.execute( + "select CrystalName from mainTable" + " where RefinementOutcome like '4%' order by CrystalName ASC" + ) + elif whichSamples.startswith("5"): + cursor.execute( + "select CrystalName from mainTable" + " where RefinementOutcome like '5%' order by CrystalName ASC" + ) + else: + cursor.execute( + "select CrystalName from mainTable" + " where RefinementOutcome like '4%'" + " or RefinementOutcome like '5%'" + " or RefinementOutcome like '6%' order by CrystalName ASC" + ) + xtalList = [] + samples = cursor.fetchall() + for sample in samples: + if str(sample[0]) not in xtalList: + xtalList.append(str(sample[0])) + return xtalList + + def get_ligand_confidence_for_ligand(self, xtal, ligChain, ligNumber, ligName): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + + sql = ( + "select " + " PANDDA_site_confidence " + "from " + " panddaTable " + "where " + " CrystalName = '%s' and " % xtal + + " PANDDA_site_ligand_chain='%s' and " % ligChain + + " PANDDA_site_ligand_sequence_number='%s' and " % ligNumber + + " PANDDA_site_ligand_resname='%s'" % ligName + ) + + cursor.execute(sql) + + ligConfidence = "not assigned" + ligs = cursor.fetchall() + for lig in ligs: + ligConfidence = lig[0] + + return ligConfidence + + def get_label_info_from_db(self): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute("select Label,Description from labelTable") + labels = cursor.fetchall() + labelList = [] + for label in labels: + labelList.append([str(label[0]), str(label[1])]) + return labelList + + def get_label_of_sample(self, xtalID): + # creates sqlite file if non existent + connect = sqlite3.connect(self.data_source_file) + cursor = connect.cursor() + cursor.execute("select label from mainTable where CrystalName is '%s'" % xtalID) + label = None + lab = cursor.fetchall() + for sample in lab: + label = sample[0] + break + return label diff --git a/xce/lib/XChemDeposit.py b/xce/lib/XChemDeposit.py new file mode 100755 index 00000000..01ebce4a --- /dev/null +++ b/xce/lib/XChemDeposit.py @@ -0,0 +1,1928 @@ +import fileinput +import glob +import os +import sys + +from PyQt4 import QtCore + +from xce.lib import XChemDB +from xce.lib import XChemLog +from xce.lib import XChemMain +from xce.lib import XChemUtils + + +class templates: + def data_template_cif(self, depositDict): + taxonomy_dict = XChemMain.NCBI_taxonomy_ID() + for key in taxonomy_dict: + if taxonomy_dict[key] == depositDict["Source_organism_scientific_name"]: + pdbx_gene_src_ncbi_taxonomy_id = key + if taxonomy_dict[key] == depositDict["Expression_system_scientific_name"]: + pdbx_host_org_ncbi_taxonomy_id = key + + audit_author_name = "" + # one name must be within quotation, last name and first initial must be + # separated by comma and space + for name in depositDict["structure_author_name"].split(";"): + if name.replace(" ", "") == "": + continue + if name[name.find(",") + 1 : name.find(",") + 2] != " ": + name = name.replace(",", ", ") + audit_author_name += "'{0!s}'\n".format(name) + + primary_citation_author_name = "" + # one name must be within quotation, last name and first initial must be + # separated by comma and space + for name in depositDict["primary_citation_author_name"].split(";"): + if name.replace(" ", "") == "": + continue + if name[name.find(",") + 1 : name.find(",") + 2] != " ": + name = name.replace(",", ", ") + primary_citation_author_name += "primary '{0!s}'\n".format(name) + + molecule_one_letter_sequence = ";" + counter = 1 + for aa in depositDict["molecule_one_letter_sequence"]: + if counter < 70: + molecule_one_letter_sequence += aa + if counter == 70: + molecule_one_letter_sequence += "\n" + aa + counter = 0 + counter += 1 + + if ( + depositDict["molecule_name_two"].replace(" ", "") == "" + or depositDict["molecule_name_two"].replace(" ", "").lower() == "none" + ): + try: + entity = ( + "loop_\n" + "_entity.id\n" + "_entity.type\n" + "_entity.src_method\n" + "_entity.pdbx_description\n" + "_entity.pdbx_mutation\n" + '1 polymer man "%s" %s\n' + % ( + depositDict["Source_organism_gene"], + depositDict["fragment_name_one_specific_mutation"], + ) + + "#\n" + "loop_\n" + "_entity_poly.entity_id\n" + "_entity_poly.type\n" + "_entity_poly.pdbx_seq_one_letter_code\n" + "_entity_poly.pdbx_strand_id\n" + "_entity_poly.pdbx_seq_db_id\n" + "_entity_poly.pdbx_seq_db_name\n" + '1 "polypeptide(L)"\n' + molecule_one_letter_sequence + "\n" + ";\n" + "%s %s UNP\n" + % ( + depositDict["protein_chains"], + depositDict["molecule_one_letter_sequence_uniprot_id"], + ) + + "#\n" + "loop_\n" + "_entity_src_gen.entity_id\n" + "_entity_src_gen.gene_src_strain\n" + "_entity_src_gen.pdbx_gene_src_scientific_name\n" + "_entity_src_gen.pdbx_gene_src_ncbi_taxonomy_id\n" + "_entity_src_gen.pdbx_host_org_scientific_name\n" + "_entity_src_gen.pdbx_host_org_ncbi_taxonomy_id\n" + '1 ? "%s" %s "%s" %s\n' + % ( + depositDict["Source_organism_scientific_name"], + pdbx_gene_src_ncbi_taxonomy_id, + depositDict["Expression_system_scientific_name"], + pdbx_host_org_ncbi_taxonomy_id, + ) + + "#\n" + ) + except UnboundLocalError: + print( + "Error: Something went wrong!" + " Please check if you have saved the .deposit file to the database:" + " Menu Deposition -> Edit Information" + ) + else: + molecule_two_letter_sequence = ";" + counter = 1 + for aa in depositDict["molecule_two_letter_sequence"]: + if counter < 70: + molecule_two_letter_sequence += aa + if counter == 70: + molecule_two_letter_sequence += "\n" + aa + counter = 0 + counter += 1 + + entity = ( + "loop_\n" + "_entity.id\n" + "_entity.type\n" + "_entity.src_method\n" + "_entity.pdbx_description\n" + "_entity.pdbx_mutation\n" + '1 polymer man "%s" %s\n' + % ( + depositDict["Source_organism_gene"], + depositDict["fragment_name_one_specific_mutation"], + ) + + '2 polymer man "%s" %s\n' + % ( + depositDict["Source_organism_gene_two"], + depositDict["fragment_name_two_specific_mutation"], + ) + + "#\n" + "loop_\n" + "_entity_poly.entity_id\n" + "_entity_poly.type\n" + "_entity_poly.pdbx_seq_one_letter_code\n" + "_entity_poly.pdbx_strand_id\n" + "_entity_poly.pdbx_seq_db_id\n" + "_entity_poly.pdbx_seq_db_name\n" + '1 "polypeptide(L)"\n' + molecule_one_letter_sequence + "\n" + ";\n" + "%s %s UNP\n" + % ( + depositDict["molecule_chain_one"], + depositDict["molecule_one_letter_sequence_uniprot_id"], + ) + + '2 "polypeptide(L)"\n' + + molecule_two_letter_sequence + + "\n" + ";\n" + "%s %s UNP\n" + % ( + depositDict["molecule_chain_two"], + depositDict["molecule_two_letter_sequence_uniprot_id"], + ) + + "#\n" + "loop_\n" + "_entity_src_gen.entity_id\n" + "_entity_src_gen.gene_src_strain\n" + "_entity_src_gen.pdbx_gene_src_scientific_name\n" + "_entity_src_gen.pdbx_gene_src_ncbi_taxonomy_id\n" + "_entity_src_gen.pdbx_host_org_scientific_name\n" + "_entity_src_gen.pdbx_host_org_ncbi_taxonomy_id\n" + '1 ? "%s" %s "%s" %s\n' + % ( + depositDict["Source_organism_scientific_name"], + pdbx_gene_src_ncbi_taxonomy_id, + depositDict["Expression_system_scientific_name"], + pdbx_host_org_ncbi_taxonomy_id, + ) + + '2 ? "%s" %s "%s" %s\n' + % ( + depositDict["Source_organism_scientific_name"], + pdbx_gene_src_ncbi_taxonomy_id, + depositDict["Expression_system_scientific_name"], + pdbx_host_org_ncbi_taxonomy_id, + ) + + "#\n" + ) + + data_template_cif = ( + "data_UNNAMED\n" + "#\n" + "_pdbx_database_status.entry_id UNNAMED\n" + "_pdbx_database_status.dep_release_code_coordinates '%s'\n" + % depositDict["Release_status_for_coordinates"] + + "_pdbx_database_status.dep_release_code_sequence '{0!s}'\n".format( + depositDict["Release_status_for_sequence"] + ) + + "#\n" + "_pdbx_deposit_group.group_id UNNAMED\n" + '_pdbx_deposit_group.group_description "%s"\n' + % depositDict["group_description"] + + '_pdbx_deposit_group.group_title "{0!s}"\n'.format( + depositDict["group_title"] + ) + + '_pdbx_deposit_group.group_type "{0!s}"\n'.format( + depositDict["group_type"] + ) + + "#\n" + "_exptl_crystal_grow.crystal_id 1\n" + "_exptl_crystal_grow.method '%s'\n" + % depositDict["crystallization_method"] + + "_exptl_crystal_grow.pH {0!s}\n".format( + depositDict["crystallization_pH"] + ) + + "_exptl_crystal_grow.temp {0!s}\n".format( + depositDict["crystallization_temperature"] + ) + + '_exptl_crystal_grow.pdbx_details "{0!s}"\n'.format( + depositDict["crystallization_details"] + ) + + "#\n" + "_diffrn.id 1\n" + "_diffrn.ambient_temp %s\n" + % depositDict["data_collection_temperature"] + + "_diffrn.crystal_id 1\n" + "#\n" + "_diffrn_source.diffrn_id 1\n" + "_diffrn_source.source %s\n" + % depositDict["radiation_source"] + + '_diffrn_source.type "{0!s}"\n'.format( + depositDict["radiation_source_type"] + ) + + "_diffrn_source.pdbx_wavelength_list {0!s}\n".format( + depositDict["radiation_wavelengths"] + ) + + "#\n" + "_diffrn_detector.detector %s\n" + % depositDict["radiation_detector"] + + "_diffrn_detector.type '{0!s}'\n".format( + depositDict["radiation_detector_type"] + ) + + "_diffrn_detector.pdbx_collection_date {0!s}\n".format( + depositDict["data_collection_date"] + ) + + "_diffrn_detector.diffrn_id 1\n" + "#\n" + "_diffrn_radiation.diffrn_id 1\n" + "_diffrn_radiation.wavelength_id 1\n" + "_diffrn_radiation.pdbx_diffrn_protocol 'SINGLE WAVELENGTH'\n" + "#\n" + "_diffrn_radiation_wavelength.id 1\n" + "_diffrn_radiation_wavelength.wavelength %s\n" + % depositDict["radiation_wavelengths"] + + "#\n" + "#\n" + entity + "loop_\n" + "_pdbx_contact_author.id \n" + "_pdbx_contact_author.address_1 \n" + "_pdbx_contact_author.address_2 \n" + "_pdbx_contact_author.city \n" + "_pdbx_contact_author.state_province \n" + "_pdbx_contact_author.postal_code \n" + "_pdbx_contact_author.email \n" + "_pdbx_contact_author.name_first \n" + "_pdbx_contact_author.name_last \n" + "_pdbx_contact_author.country \n" + "_pdbx_contact_author.phone \n" + "_pdbx_contact_author.role \n" + "_pdbx_contact_author.organization_type \n" + "_pdbx_contact_author.identifier_ORCID \n" + "1 '%s' '%s' '%s' '?' '%s' %s %s '%s' '%s' '%s' '%s' %s %s\n" + % ( + depositDict["contact_author_PI_address"], + depositDict["contact_author_PI_organization_name"], + depositDict["contact_author_PI_city"], + depositDict["contact_author_PI_Zip_Code"], + depositDict["contact_author_PI_email"], + depositDict["contact_author_PI_first_name"], + depositDict["contact_author_PI_last_name"], + depositDict["contact_author_PI_Country"], + depositDict["contact_author_PI_phone_number"], + depositDict["contact_author_PI_role"], + depositDict["contact_author_PI_organization_type"], + depositDict["contact_author_PI_ORCID"], + ) + + "2 '{0!s}' '{1!s}' '{2!s}' '?' '{3!s}' '{4!s}' {5!s}" + " {6!s} '{7!s}' '{8!s}' '{9!s}' '{10!s}' {11!s}\n".format( + depositDict["contact_author_address"], + depositDict["contact_author_organization_name"], + depositDict["contact_author_city"], + depositDict["contact_author_Zip_Code"].replace(" ", ""), + depositDict["contact_author_email"], + depositDict["contact_author_first_name"], + depositDict["contact_author_last_name"], + depositDict["contact_author_Country"], + depositDict["contact_author_phone_number"], + depositDict["contact_author_role"], + depositDict["contact_author_organization_type"], + depositDict["contact_author_ORCID"], + ) + + "#\n" + "loop_\n" + "_audit_author.name\n" + audit_author_name + "#\n" + "_citation.id primary\n" + "_citation.title '%s'\n" % depositDict["group_title"] + + "_citation.journal_abbrev 'To Be Published'\n" + "#\n" + "loop_\n" + "_citation_author.citation_id\n" + "_citation_author.name\n" + primary_citation_author_name + "#\n" + "_struct.entry_id UNNAMED\n" + "_struct.title\n" + ";%s\n" % depositDict["title"] + ";\n" + "#\n" + "_struct_keywords.entry_id UNNAMED\n" + '_struct_keywords.text "%s"\n' + % depositDict["structure_keywords"] + + "#\n" + "_pdbx_struct_assembly_depositor_info.id 1\n" + "_pdbx_struct_assembly_depositor_info.method_details PISA\n" + "_pdbx_struct_assembly_depositor_info.oligomeric_count %s\n" + % depositDict["biological_assembly_chain_number"] + + "#\n" + ) + + return data_template_cif + + +class update_depositTable(QtCore.QThread): + def __init__(self, deposit_dict, database, xce_logfile): + QtCore.QThread.__init__(self) + self.deposit_dict = deposit_dict + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source(database) + + def run(self): + self.Logfile.insert( + "all entries in the depositTable will be updated with the following values:" + ) + for key in self.deposit_dict: + self.Logfile.insert(key + ": " + self.deposit_dict[key]) + dbEntries = self.db.execute_statement( + "select CrystalName,StructureType from depositTable;" + ) + for item in dbEntries: + xtal = str(item[0]) + type = str(item[1]) + # need to do this because individual fields might need updating + # for some xtals + db_dict = self.deposit_dict + + # try to get information about the diffraction experiment + try: + diffractionExperiment = self.db.execute_statement( + "select DataCollectionBeamline,DataCollectionDate" + " from mainTable where CrystalName is '{0!s}'".format(xtal) + ) + beamline = str(diffractionExperiment[0][0]) + date = str(diffractionExperiment[0][1]) + except (UnboundLocalError, IndexError): + self.Logfile.warning( + "%s: cannot find details about diffraction experiment in mainTable" + % xtal + ) + beamline = db_dict["radiation_source"] + date = db_dict["data_collection_date"] + self.Logfile.warning( + "%s: using values provided in depositTable for beamline" + " and data collection date" % xtal + ) + if beamline.lower() != "none": + db_dict = self.tweak_deposit_dict(xtal, db_dict) + if date.lower() != "none": + db_dict["data_collection_date"] = date.split()[0] + + self.Logfile.insert("updating depositTable for " + xtal + " @ " + type) + self.db.update_depositTable(xtal, type, db_dict) + self.Logfile.insert("Note: use DBbrowser to edit individual entries") + + def tweak_deposit_dict(self, xtal, db_dict): + dls_beamlines = ["i02", "i03", "i04", "i04-1", "i23", "i24"] + dls_beamline_dict = { + "i02": ["DIAMOND BEAMLINE I02", "DECTRIS PILATUS 6M"], + "i03": ["DIAMOND BEAMLINE I03", "DECTRIS EIGER2 XE 16M"], + "i04": ["DIAMOND BEAMLINE I04", "DECTRIS EIGER2 XE 16M"], + "i04-1": ["DIAMOND BEAMLINE I04-1", "DECTRIS EIGER2 XE 9M"], + "i23": ["DIAMOND BEAMLINE I23", "DECTRIS PILATUS 12M"], + "i24": ["DIAMOND BEAMLINE I24", "DECTRIS PILATUS 6M"], + } + + if db_dict["radiation_source_type"] in dls_beamlines: + db_dict["radiation_source_type"] = dls_beamline_dict[ + db_dict["radiation_source_type"] + ][0] + db_dict["radiation_detector_type"] = dls_beamline_dict[ + db_dict["radiation_source_type"] + ][1] + db_dict["radiation_detector"] = "PIXEL" + db_dict["radiation_source"] = "SYNCHROTRON" + + return db_dict + + +class prepare_mmcif_files_for_deposition(QtCore.QThread): + def __init__( + self, + database, + xce_logfile, + overwrite_existing_mmcif, + projectDir, + ground_state, + ignore_event_map, + ): + QtCore.QThread.__init__(self) + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source(database) + self.overwrite_existing_mmcif = overwrite_existing_mmcif + self.projectDir = projectDir + self.data_template_dict = {} + + self.errorList = [] + self.eventList = [] + self.db_dict = None + self.data_template_dict = None + self.pdb = None + self.mtz = None + self.logDir = None + + self.ground_state = False + self.ground_state_pdb = "" + self.panddaDir = "" + self.ignore_event_map = ignore_event_map + if ground_state: + self.ground_state = True + self.ground_state_pdb = ground_state[0] + self.ground_state_mtz = ground_state[1] + self.panddaDir = ground_state[2] + self.logDir = self.projectDir + self.projectDir = self.panddaDir + self.pdb = XChemUtils.pdbtools(self.ground_state_pdb) + self.mtz = XChemUtils.mtztools(self.ground_state_mtz) + + def run(self): + self.Logfile.insert( + "======= preparing mmcif files for wwPDB deposition =======" + ) + self.Logfile.insert("checking DB for structures to deposit...") + if self.ground_state: + toDeposit = self.db.execute_statement( + "select CrystalName from depositTable where DimplePANDDApath = '%s';" + % self.panddaDir + ) + else: + toDeposit = self.db.execute_statement( + "select CrystalName from mainTable where RefinementOutcome like '5%';" + ) + self.Logfile.insert( + "found " + str(len(toDeposit)) + " samples ready for deposition" + ) + + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + for item in sorted(toDeposit): + xtal = str(item[0]) + if self.ground_state: + os.chdir(self.projectDir) + else: + os.chdir(os.path.join(self.projectDir, xtal)) + self.Logfile.insert("%s: ----- preparing files for deposition -----" % xtal) + + if self.ground_state: + if not self.data_template_dict_exists(xtal): + continue + + if not self.save_data_template_dict(xtal): + continue + + if not self.create_model_mmcif(xtal): + continue + + self.add_funding_information(xtal) + + if not self.apo_mmcif_exists(): + continue + + if not self.add_apo_sf_mmcif_to_ground_state_mmcif(): + continue + + if not self.add_data_increment_to_apo_mmcif(xtal): + continue + + else: + if not self.mmcif_files_can_be_replaced(xtal): + continue + + if not self.data_template_dict_exists(xtal): + continue + + if not self.db_dict_exists(xtal): + continue + + if not self.refine_bound_exists(xtal): + continue + + if not self.refine_mtz_exists(xtal): + continue + + if not self.mtzFree_exists(xtal): + continue + + if not self.aimless_logfile_exists(xtal): + continue + + if not self.ligand_in_pdb_file(xtal): + continue + + if not self.eventMTZ_exists((xtal)): + continue + + if not self.find_matching_event_map(xtal): + continue + + if not self.save_data_template_dict(xtal): + continue + + if not self.create_model_mmcif(xtal): + continue + + self.add_funding_information(xtal) + + if not self.add_ligand_cif_to_model_mmcif(xtal): + continue + + if not self.create_sf_mmcif(xtal): + continue + + if not self.event_maps_exist_in_sf_mmcif(xtal): + continue + + self.make_table_one(xtal) + + self.print_errorlist() + self.Logfile.insert( + "======= finished preparing mmcif files for wwPDB deposition =======" + ) + + def data_template_dict_exists(self, xtal): + dictStatus = False + self.data_template_dict = None + self.Logfile.insert( + "%s: reading information from depositTable for sample" % xtal + ) + self.data_template_dict = self.db.get_deposit_dict_for_sample(xtal) + if self.data_template_dict == {}: + self.Logfile.error( + "%s: cannot find data_template dictionary in depositTable;" + " moving to next dataset..." % xtal + ) + self.add_to_errorList(xtal) + else: + self.Logfile.insert( + "%s: found data_template dictionary in depositTable" % xtal + ) + dictStatus = True + return dictStatus + + def update_beamline_info_data_template_dict(self, xtal): + dls_beamlines = ["i02", "i03", "i04", "i04-1", "i23", "i24"] + dls_beamline_dict = { + "i02": ["DIAMOND BEAMLINE I02", "DECTRIS PILATUS 6M"], + "i03": ["DIAMOND BEAMLINE I03", "DECTRIS EIGER2 XE 16M"], + "i04": ["DIAMOND BEAMLINE I04", "DECTRIS EIGER2 XE 16M"], + "i04-1": ["DIAMOND BEAMLINE I04-1", "DECTRIS EIGER2 XE 9M"], + "i23": ["DIAMOND BEAMLINE I23", "DECTRIS PILATUS 12M"], + "i24": ["DIAMOND BEAMLINE I24", "DECTRIS PILATUS 6M"], + } + + if self.db_dict["DataCollectionBeamline"] in dls_beamlines: + self.data_template_dict["radiation_source_type"] = dls_beamline_dict[ + self.db_dict["DataCollectionBeamline"] + ][0] + self.data_template_dict["radiation_detector_type"] = dls_beamline_dict[ + self.db_dict["DataCollectionBeamline"] + ][1] + self.data_template_dict["radiation_detector"] = "PIXEL" + self.data_template_dict["radiation_source"] = "SYNCHROTRON" + self.Logfile.insert( + ( + "%s: setting data collection beamline to %s" + % (xtal, self.data_template_dict["radiation_source_type"]) + ) + ) + + def db_dict_exists(self, xtal): + dictStatus = False + self.db_dict = None + self.Logfile.insert("%s: reading information from mainTable for sample" % xtal) + self.db_dict = self.db.get_db_dict_for_sample(xtal) + if self.db_dict == {}: + self.Logfile.error( + "%s: cannot find db_dict dictionary in mainTable;" + " moving to next dataset..." % xtal + ) + self.add_to_errorList(xtal) + else: + self.Logfile.insert("%s: found db_dict dictionary in mainTable" % xtal) + self.update_beamline_info_data_template_dict(xtal) + dictStatus = True + return dictStatus + + def mmcif_files_can_be_replaced(self, xtal): + status = True + if self.overwrite_existing_mmcif: + self.Logfile.insert( + "%s: removing existing mmcif files as chosen by user" % xtal + ) + self.db.execute_statement( + "update depositTable set mmCIF_model_file='',mmCIF_SF_file=''" + " where CrystalName is '{0!s}'".format(xtal) + ) + for mmcif in glob.glob("*.mmcif"): + self.Logfile.warning("%s: removing %s" % (xtal, mmcif)) + os.system("/bin/rm " + mmcif) + else: + for mmcif in glob.glob("*.mmcif"): + self.Logfile.warning("%s: %s exists; skipping..." % (xtal, mmcif)) + status = False + return status + + def refine_bound_exists(self, xtal): + self.pdb = None + self.Logfile.insert( + "%s: checking if refine.split.bound-state.pdb exists" % xtal + ) + fileStatus = False + if os.path.isfile("refine.split.bound-state.pdb"): + self.Logfile.insert("%s: found refine.split.bound-state.pdb" % xtal) + self.pdb = XChemUtils.pdbtools("refine.split.bound-state.pdb") + fileStatus = True + else: + self.Logfile.error( + "%s: cannot find refine.split.bound-state.pdb;" + " moving to next dataset..." % xtal + ) + self.add_to_errorList(xtal) + return fileStatus + + def refine_mtz_exists(self, xtal): + self.mtz = None + self.Logfile.insert("%s: checking if refine.mtz exists" % xtal) + fileStatus = False + if os.path.isfile("refine.mtz"): + self.Logfile.insert("%s: found refine.mtz" % xtal) + self.mtz = XChemUtils.mtztools("refine.mtz") + fileStatus = True + else: + self.Logfile.error( + "%s: cannot find refine.mtz; moving to next dataset..." % xtal + ) + self.add_to_errorList(xtal) + return fileStatus + + def run_aimless_merge_only(self, xtal, unmerged, APpath): + cmd = ( + "aimless hklin %s hklout mergeonly.mtz << eof > %s\n" + % (unmerged, unmerged.replace(".mtz", ".log")) + + " onlymerge\n" + "eof" + ) + self.Logfile.insert("%s: running AIMLESS in onlymerge mode..." % xtal) + os.system(cmd) + os.chdir(os.path.join(self.projectDir, xtal)) + os.system("/bin/rm %s.log" % xtal) + os.system( + "ln -s %s/%s %s.log" % (APpath, unmerged.replace(".mtz", ".log"), xtal) + ) + self.Logfile.insert("%s: finished running AIMLESS" % xtal) + if os.path.isfile(xtal + ".log"): + self.Logfile.insert("%s: AIMLESS logfile successfully created" % xtal) + else: + self.Logfile.error("%s: cannot find AIMLESS logfile..." % xtal) + + def prepare_aimless_log(self, xtal): + XChemUtils.parse().make_pseudo_aimless_log_from_json(xtal + ".log") + + def aimless_logfile_exists(self, xtal): + self.Logfile.insert( + "%s: checking if aimless logfile, i.e. %s.log, exists" % (xtal, xtal) + ) + fileStatus = False + if os.path.isfile("%s.log" % xtal): + self.Logfile.insert("%s: found %s.log" % (xtal, xtal)) + for n, line in enumerate(open("%s.log" % xtal)): + if "AIMLESS" in line: + fileStatus = True + break + if not fileStatus: + if os.path.realpath("%s.log" % xtal).endswith(".table1"): + self.Logfile.warning( + "{0!s}: {1!s}.log seems to be a staraniso .table1 file".format( + xtal, xtal + ) + ) + fileStatus = True + if not fileStatus: + self.Logfile.warning( + "%s: this does not seem to be an AIMLESS logfile" % xtal + ) + Filepath = os.path.relpath(os.path.realpath("%s.log" % xtal)) + APpath = Filepath[: Filepath.rfind("/")] + self.Logfile.insert("%s: relative path to logfile %s" % (xtal, APpath)) + self.Logfile.insert("%s: file path to logfile %s" % (xtal, Filepath)) + if os.path.isdir(APpath): + os.chdir(APpath) + for unmerged in glob.glob("*_scaled_unmerged.mtz"): + self.Logfile.insert( + "%s: found %s in %s" % (xtal, unmerged, APpath) + ) + self.run_aimless_merge_only(xtal, unmerged, APpath) + fileStatus = True + break + else: + self.Logfile.error("%s: %s is not a directory" % (xtal, APpath)) + self.add_to_errorList(xtal) + if not fileStatus: + os.chdir(os.path.join(self.projectDir, xtal)) + self.Logfile.insert( + "%s: trying to prepare a pseudo-aimless file from json file..." + % xtal + ) + self.prepare_aimless_log(xtal) + if os.path.isfile("aimless_dials.log"): + self.Logfile.insert("%s: found aimless_dials.log" % xtal) + fileStatus = True + if not fileStatus: + self.Logfile.error( + "%s: cannot find a suitable AIMLESS logfile" % xtal + ) + self.add_to_errorList(xtal) + else: + self.Logfile.error( + "%s: cannot find %s.log; moving to next dataset..." % (xtal, xtal) + ) + self.add_to_errorList(xtal) + return fileStatus + + def mtzFree_exists(self, xtal): + self.Logfile.insert("%s: checking if %s.free.mtz exists" % (xtal, xtal)) + fileStatus = False + if os.path.isfile("%s.free.mtz" % xtal): + self.Logfile.insert("%s: found %s.free.mtz" % (xtal, xtal)) + fileStatus = True + else: + self.Logfile.error( + "%s: cannot find %s.free.mtz; moving to next dataset..." % (xtal, xtal) + ) + self.add_to_errorList(xtal) + return fileStatus + + def ligand_in_pdb_file(self, xtal): + self.Logfile.insert( + "%s: checking if refine.split.bound-state.pdb contains ligands of type LIG" + % xtal + ) + ligandStatus = False + ligList = XChemUtils.pdbtools( + "refine.split.bound-state.pdb" + ).get_residues_with_resname("LIG") + if ligList is []: + self.Logfile.error( + "%s: refine.split.bound-state.pdb does not contain any modelled ligands" + " of type LIG" % xtal + ) + self.add_to_errorList(xtal) + else: + self.Logfile.insert( + xtal + ": found " + str(len(ligList)) + " ligands of type LIG" + ) + ligandStatus = True + return ligandStatus + + def eventMTZ_exists(self, xtal): + self.Logfile.insert("%s: checking if mtz of event maps exists" % xtal) + eventMTZlist = [] + eventMTZexists = False + if os.path.isfile("no_pandda_analysis_performed") or self.ignore_event_map: + self.Logfile.warning( + '%s: found empty file named "no_pandda_analysis_performed"' + " which suggests we will ignore event maps for this sample" % xtal + ) + eventMTZexists = True + elif self.ignore_event_map: + self.Logfile.warning( + "%s: user selected to not include event map in SF mmcif file" % xtal + ) + eventMTZexists = True + else: + for mtz in glob.glob("*event*.native*.mtz"): + eventMTZlist.append(mtz[mtz.rfind("/") + 1 :]) + if eventMTZlist is []: + self.Logfile.error( + "%s: MTZ files of event maps do not exists!" + ' Go to PANDDA tab and run "Event Map -> SF"' % xtal + ) + self.add_to_errorList(xtal) + else: + self.Logfile.insert( + xtal + + ": found " + + str(len(eventMTZlist)) + + " MTZ files of event maps" + ) + eventMTZexists = True + return eventMTZexists + + def find_matching_event_map(self, xtal): + self.eventList = [] + self.Logfile.insert( + "%s: trying to find fitting event maps for modelled ligands" % xtal + ) + ligList = self.pdb.save_residues_with_resname( + os.path.join(self.projectDir, xtal), "LIG" + ) + foundMatchingMap = None + if os.path.isfile("no_pandda_analysis_performed") or self.ignore_event_map: + self.Logfile.warning( + '%s: found empty file named "no_pandda_analysis_performed"' + " which suggests we will ignore event maps for this sample" % xtal + ) + foundMatchingMap = True + ligList = [] + + self.Logfile.insert( + "%s: looking for event maps for the following ligands -> %s" + % (xtal, str(ligList)) + ) + for lig in sorted(ligList): + ligID = lig.replace(".pdb", "") + ligCC = [] + for mtz in glob.glob( + ("%s-event_*.native_%s.mtz" % (xtal, lig.replace(".pdb", ""))) + ): + self.Logfile.insert(xtal + ": found " + mtz) + foundMatchingMap = True + self.eventList.append(mtz) + break + + if foundMatchingMap: + continue + + for mtz in sorted(glob.glob("*event*.native.mtz")): + self.get_lig_cc(xtal, mtz, lig) + cc = self.check_lig_cc(mtz.replace(".mtz", "_CC" + ligID + ".log")) + self.Logfile.insert("%s: %s -> CC = %s for %s" % (xtal, ligID, cc, mtz)) + try: + ligCC.append([mtz, float(cc)]) + except ValueError: + ligCC.append([mtz, 0.00]) + + for mtz in sorted(glob.glob("*event*.native*P1.mtz")): + self.get_lig_cc(xtal, mtz, lig) + cc = self.check_lig_cc(mtz.replace(".mtz", "_CC" + ligID + ".log")) + self.Logfile.insert("%s: %s -> CC = %s for %s" % (xtal, ligID, cc, mtz)) + try: + ligCC.append([mtz, float(cc)]) + except ValueError: + ligCC.append([mtz, 0.00]) + try: + for cm in ligCC: + self.Logfile.insert("%s: cc = %s - %s" % (xtal, cm[1], cm[0])) + highestCCeventmap = max(ligCC, key=lambda x: float(x[1]))[0] + except ValueError: + highestCCeventmap = None + if highestCCeventmap is None or ligCC is []: + self.Logfile.error( + "%s: best CC of ligand %s for any event map is 0!" % (xtal, lig) + ) + self.add_to_errorList(xtal) + foundMatchingMap = False + else: + self.Logfile.insert( + "%s: selected event map for ligand %s is %s" + % (xtal, lig, highestCCeventmap) + ) + if os.path.isfile( + highestCCeventmap.replace(".mtz", "_" + ligID + ".mtz") + ): + self.Logfile.warning( + "%s: symlink exists %s" + % ( + xtal, + highestCCeventmap.replace(".mtz", "_" + ligID + ".mtz"), + ) + ) + else: + self.Logfile.insert( + "%s: making symlink %s" + % ( + xtal, + highestCCeventmap.replace(".mtz", "_" + ligID + ".mtz"), + ) + ) + os.system( + "ln -s %s %s" + % ( + highestCCeventmap, + highestCCeventmap.replace(".mtz", "_" + ligID + ".mtz"), + ) + ) + if highestCCeventmap not in self.eventList: + self.eventList.append(highestCCeventmap) + if foundMatchingMap is None: + foundMatchingMap = True + return foundMatchingMap + + def get_lig_cc(self, xtal, mtz, lig): + ligID = lig.replace(".pdb", "") + self.Logfile.insert("%s: calculating CC for %s in %s" % (xtal, lig, mtz)) + if os.path.isfile(mtz.replace(".mtz", "_CC" + ligID + ".log")): + self.Logfile.warning("logfile of CC analysis exists; skipping...") + return + cmd = "module load phenix/1.20\n" "phenix.get_cc_mtz_pdb %s %s > %s" % ( + mtz, + lig, + mtz.replace(".mtz", "_CC" + ligID + ".log"), + ) + os.system(cmd) + + def check_lig_cc(self, log): + cc = "n/a" + if os.path.isfile(log): + for line in open(log): + if line.startswith("local"): + cc = line.split()[len(line.split()) - 1] + else: + self.Logfile.error("logfile does not exist: %s" % log) + return cc + + def add_to_errorList(self, xtal): + if xtal.replace(" ", "") == "": + self.Logfile.warning( + "trying to add xtal to error list, but xtal string is empty" + ) + else: + if xtal not in self.errorList: + self.errorList.append(xtal) + + def print_errorlist(self): + if not self.errorList: + self.Logfile.insert( + "XCE did not detect any problems during mmcif file preparation. " + "It is however recommended to check the logfile." + ) + else: + self.Logfile.warning( + "The following samples had problems during mmcif creation. " + "Please check the logfile for details!" + ) + for xtal in self.errorList: + self.Logfile.error(xtal) + + def save_data_template_dict(self, xtal): + # check if file exists + noError = True + self.Logfile.insert("%s: preparing data_template.cif file" % xtal) + if self.overwrite_existing_mmcif: + self.data_template_dict["radiation_wavelengths"] = self.mtz.get_wavelength() + if str(self.data_template_dict["radiation_wavelengths"]).startswith("0.0"): + self.Logfile.error( + "%s: this does not seem to be the true experimental wavelength: %s" + % (xtal, str(self.data_template_dict["radiation_wavelengths"])) + ) + self.Logfile.insert( + "%s: trying to find it from %s.free.mtz..." % (xtal, xtal) + ) + if os.path.isfile("%s.free.mtz" % xtal): + self.data_template_dict[ + "radiation_wavelengths" + ] = XChemUtils.mtztools(xtal + ".free.mtz").get_wavelength() + self.Logfile.warning( + "%s: found the following wavelength -> %s" + % (xtal, str(self.data_template_dict["radiation_wavelengths"])) + ) + self.Logfile.insert( + "%s: experimental wavelength according to %s is %s" + % (xtal, self.mtz, self.data_template_dict["radiation_wavelengths"]) + ) + if self.ground_state: + os.chdir(self.projectDir) + self.data_template_dict["group_type"] = "ground state" + self.data_template_dict[ + "group_title" + ] = "PanDDA analysis group deposition of ground-state model" + self.data_template_dict["group_description"] = self.data_template_dict[ + "group_description" + ].replace( + "$ProteinName", self.data_template_dict["Source_organism_gene"] + ) + self.data_template_dict["title"] = self.data_template_dict[ + "structure_title_apo" + ].replace( + "$ProteinName", self.data_template_dict["Source_organism_gene"] + ) + else: + os.chdir(os.path.join(self.projectDir, xtal)) + + title = ( + self.data_template_dict["structure_title"] + .replace( + "$ProteinName", self.data_template_dict["Source_organism_gene"] + ) + .replace("$CompoundName", self.db_dict["CompoundCode"]) + .replace("($SampleID)", "(" + xtal + ")") + ) + + self.data_template_dict["group_type"] = "changed state" + + # edit title + self.data_template_dict["group_title"] = ( + self.data_template_dict["group_deposition_title"] + .replace( + "$ProteinName", self.data_template_dict["Source_organism_gene"] + ) + .replace("$CompoundName", self.db_dict["CompoundCode"]) + ) + + self.data_template_dict["group_description"] = self.data_template_dict[ + "group_description" + ].replace( + "$ProteinName", self.data_template_dict["Source_organism_gene"] + ) + self.data_template_dict["title"] = ( + self.data_template_dict["group_title"] + " -- " + title + ) + + if ("$ProteinName" or "$CompoundName") in self.data_template_dict[ + "title" + ]: + self.Logfile.error( + "%s: data_template - title not correctly formatted" + ) + self.add_to_errorList(xtal) + noError = False + + # mutations + mutations = self.data_template_dict["fragment_name_one_specific_mutation"] + if ( + mutations.lower() + .replace(" ", "") + .replace("none", "") + .replace("null", "") + == "" + ): + self.data_template_dict["fragment_name_one_specific_mutation"] = "?" + else: + self.data_template_dict["fragment_name_one_specific_mutation"] = ( + '"' + mutations.replace(" ", "") + '"' + ) + + # get protein chains + self.data_template_dict["protein_chains"] = "" + chains = self.pdb.GetProteinChains() + for item in chains: + self.data_template_dict["protein_chains"] += item + "," + self.data_template_dict["protein_chains"] = self.data_template_dict[ + "protein_chains" + ][:-1] + + data_template = templates().data_template_cif(self.data_template_dict) + if self.ground_state: + f = open(os.path.join(self.projectDir, "data_template.cif"), "w") + else: + f = open(os.path.join(self.projectDir, xtal, "data_template.cif"), "w") + + f.write(data_template) + f.close() + + return noError + + def create_model_mmcif(self, xtal): + fileStatus = False + if self.ground_state: + os.chdir(os.path.join(self.projectDir)) + else: + os.chdir(os.path.join(self.projectDir, xtal)) + refSoft = self.pdb.get_refinement_program() + + pdb_extract_init = ( + "source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n" + "pdb_extract" + ) + + if self.ground_state: + refXtal = self.ground_state_pdb.split("/")[ + len(self.ground_state_pdb.split("/")) - 2 + ] + self.Logfile.insert( + "ground_state deposition reference dataset: {0!s}".format(refXtal) + ) + aimless = os.path.join(self.logDir, refXtal, refXtal + ".log") + else: + aimless = "%s.log" % xtal + + isAimlessFile = False + for n, line in enumerate(open(aimless)): + if "AIMLESS" in line: + isAimlessFile = True + break + if not isAimlessFile: + self.Logfile.warning( + "processing log file does not seem to be an aimless file: {0!s}".format( + aimless + ) + ) + self.Logfile.insert( + "realpath of processing logfile: {0!s}".format( + os.path.realpath(aimless) + ) + ) + if os.path.realpath(aimless).endswith(".table1"): + self.Logfile.warning( + "{0!s}: {1!s}.log seems to be a staraniso .table1 file".format( + xtal, xtal + ) + ) + isAimlessFile = True + self.Logfile.warning("it does not seem to originate from staraniso either") + if not isAimlessFile: + if os.path.isfile("aimless_dials.log"): + aimless = "aimless_dials.log" + else: + XChemUtils.parse().make_pseudo_aimless_log_from_json(aimless) + aimless = "aimless_dials.log" + + if self.ground_state: + self.Logfile.insert("aimless.log file: " + aimless) + Cmd = ( + pdb_extract_init + + " -r {0!s}".format(refSoft) + + " -iPDB {0!s}".format(self.ground_state_pdb) + + " -e MR" + " -s AIMLESS" + " -iLOG {0!s}".format(aimless) + " -iENT data_template.cif" + " -o {0!s}.mmcif > {1!s}.mmcif.log".format(xtal, xtal) + ) + else: + Cmd = ( + pdb_extract_init + + " -r {0!s}".format(refSoft) + + " -iPDB {0!s}".format("refine.split.bound-state.pdb") + + " -e MR" + " -s AIMLESS" + " -iLOG {0!s}".format(aimless) + " -iENT data_template.cif" + " -o {0!s}.mmcif > {1!s}.mmcif.log".format(xtal, xtal) + ) + + self.Logfile.insert(xtal + ": running pdb_extract: " + Cmd) + os.system(Cmd) + + self.update_model_mmcif_header(xtal) + + if os.path.isfile(xtal + ".mmcif") and os.path.getsize(xtal + ".mmcif") > 20000: + self.Logfile.insert("%s: model mmcif file successfully created" % xtal) + if self.ground_state: + self.db.execute_statement( + "update depositTable set mmCIF_model_file='{0!s}.mmcif'" + " where CrystalName is '{1!s}'" + " and DimplePANDDApath is '{2!s}'".format( + xtal, xtal, self.panddaDir + ) + ) + else: + self.db.execute_statement( + "update depositTable set mmCIF_model_file='{0!s}.mmcif'" + " where CrystalName is '{1!s}'".format(xtal, xtal) + ) + fileStatus = True + else: + self.Logfile.error("%s: model mmcif file was not created successfully") + self.add_to_errorList(xtal) + + return fileStatus + + def update_model_mmcif_header(self, xtal): + self.Logfile.insert("%s: updating header of model mmcif file" % xtal) + foundSoftwareBlock = False + amendSoftwareBlock = False + softwareEntry = [] + for i, line in enumerate(fileinput.input(xtal + ".mmcif", inplace=1)): + if "_software.pdbx_ordinal" in line: + foundSoftwareBlock = True + if foundSoftwareBlock: + if not line.startswith("_"): + try: + softwareEntry.append(int(line.split()[0])) + except (ValueError, IndexError): + pass + if "#" in line: + amendSoftwareBlock = True + foundSoftwareBlock = False + if "_refine.pdbx_ls_cross_valid_method" in line: + sys.stdout.write( + "_refine.pdbx_ls_cross_valid_method THROUGHOUT \n" + ) + + elif "_refine.pdbx_starting_model" in line: + sys.stdout.write( + "_refine.pdbx_starting_model {0!s} \n".format( + self.data_template_dict["pdbx_starting_model"] + ) + ) + + elif "_refine.pdbx_method_to_determine_struct" in line: + sys.stdout.write( + "_refine.pdbx_method_to_determine_struct" + " 'FOURIER SYNTHESIS'\n" + ) + elif "_struct.title ---" in line: + Title = "" + foundTitle = False + for li in open("data_template.cif"): + if li.startswith("_struct.title"): + foundTitle = True + if foundTitle: + if ( + li.replace(" ", "").replace("\n", "").replace("\r", "") + == ";" + ): + Title += li + break + Title += li + sys.stdout.write(Title) + elif amendSoftwareBlock: + cifItem = "{0!s} {1!s} ? ? program ? ? 'data reduction' ? ?\n".format( + str(max(softwareEntry) + 1), + self.data_template_dict["data_integration_software"], + ) + "{0!s} {1!s} ? ? program ? ? phasing ? ?\n".format( + str(max(softwareEntry) + 2), + self.data_template_dict["phasing_software"], + ) + + sys.stdout.write(cifItem) + amendSoftwareBlock = False + + else: + sys.stdout.write(line) + + def add_funding_information(self, xtal): + pdbx_funding_ordinal_one = self.data_template_dict["pdbx_funding_ordinal_one"] + if ( + pdbx_funding_ordinal_one.lower() + .replace(" ", "") + .replace("none", "") + .replace("null", "") + == "" + ): + self.data_template_dict["pdbx_funding_ordinal_one"] = "" + self.data_template_dict["pdbx_funding_organization_one"] = "" + self.data_template_dict["pdbx_grant_number_one"] = "" + self.data_template_dict["pdbx_grant_country_one"] = "" + funding_one = "" + else: + funding_one = "%s '%s' '%s' '%s'\n" % ( + self.data_template_dict["pdbx_funding_ordinal_one"], + self.data_template_dict["pdbx_funding_organization_one"], + self.data_template_dict["pdbx_grant_number_one"], + self.data_template_dict["pdbx_grant_country_one"], + ) + + pdbx_funding_ordinal_two = self.data_template_dict["pdbx_funding_ordinal_two"] + if ( + pdbx_funding_ordinal_two.lower() + .replace(" ", "") + .replace("none", "") + .replace("null", "") + == "" + ): + self.data_template_dict["pdbx_funding_ordinal_two"] = "" + self.data_template_dict["pdbx_funding_organization_two"] = "" + self.data_template_dict["pdbx_grant_number_two"] = "" + self.data_template_dict["pdbx_grant_country_two"] = "" + funding_two = "" + else: + funding_two = "%s '%s' '%s' '%s'\n" % ( + self.data_template_dict["pdbx_funding_ordinal_two"], + self.data_template_dict["pdbx_funding_organization_two"], + self.data_template_dict["pdbx_grant_number_two"], + self.data_template_dict["pdbx_grant_country_two"], + ) + + pdbx_funding_ordinal_three = self.data_template_dict[ + "pdbx_funding_ordinal_three" + ] + if ( + pdbx_funding_ordinal_three.lower() + .replace(" ", "") + .replace("none", "") + .replace("null", "") + == "" + ): + self.data_template_dict["pdbx_funding_ordinal_three"] = "" + self.data_template_dict["pdbx_funding_organization_three"] = "" + self.data_template_dict["pdbx_grant_number_three"] = "" + self.data_template_dict["pdbx_grant_country_three"] = "" + funding_three = "" + else: + funding_three = "%s '%s' '%s' '%s'\n" % ( + self.data_template_dict["pdbx_funding_ordinal_three"], + self.data_template_dict["pdbx_funding_organization_three"], + self.data_template_dict["pdbx_grant_number_three"], + self.data_template_dict["pdbx_grant_country_three"], + ) + + funding_info = ( + "#\n" + "loop_\n" + "_pdbx_audit_support.ordinal \n" + "_pdbx_audit_support.funding_organization \n" + "_pdbx_audit_support.grant_number \n" + "_pdbx_audit_support.country \n" + + funding_one + + funding_two + + funding_three + + "#\n" + ) + + f = open(xtal + ".mmcif", "a") + f.write(funding_info) + f.close() + + def add_ligand_cif_to_model_mmcif(self, xtal): + filestatus = False + self.Logfile.insert("%s: looking for ligand restraints file..." % xtal) + os.chdir(os.path.join(self.projectDir, xtal)) + if os.path.isfile(self.db_dict["RefinementMMCIFmodel_latest"]): + self.Logfile.insert( + "%s: found %s; assuming that ligand cif dictionary" + " is already included..." + % (xtal, self.db_dict["RefinementMMCIFmodel_latest"]) + ) + filestatus = True + else: + if os.path.isfile(self.db_dict["CompoundCode"] + ".cif"): + self.Logfile.insert( + "%s: found ligand restraints file -> %s" + % (xtal, self.db_dict["CompoundCode"] + ".cif") + ) + self.Logfile.insert( + "%s: adding ligand restraints file to model mmcif" % xtal + ) + cif = "" + for line in open(self.db_dict["CompoundCode"] + ".cif"): + cif += line + f = open(xtal + ".mmcif", "a") + f.write(cif) + f.close() + filestatus = True + else: + self.Logfile.warning( + "%s: could not find %s" + % (xtal, self.db_dict["CompoundCode"] + ".cif") + ) + return filestatus + + def make_table_one(self, xtal): + os.chdir(os.path.join(self.projectDir, xtal)) + if os.path.isfile(xtal + ".mmcif") and os.path.getsize(xtal + ".mmcif") > 20000: + self.Logfile.insert("making table_1 for %s.mmcif" % xtal) + + Cmd = ( + "source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n" + "extract_table" + " " + xtal + ".mmcif" + ) + + self.Logfile.insert(xtal + ": running sf_convert: " + Cmd) + os.system(Cmd) + + if os.path.isfile("cryst-table-1.out"): + os.system("/bin/mv cryst-table-1.out %s-table-1.txt" % xtal) + self.Logfile.insert( + "%s: table_1 successfully created; updating database..." % xtal + ) + self.db.execute_statement( + "update mainTable set table_one='{0!s}-table-1.txt'" + " where CrystalName is '{1!s}'".format(xtal, xtal) + ) + else: + self.Logfile.warning("%s: could not create table_1" % xtal) + + def create_sf_mmcif(self, xtal): + fileStatus = False + if self.ground_state: + os.chdir(self.projectDir) + else: + os.chdir(os.path.join(self.projectDir, xtal)) + + if os.path.isfile("no_pandda_analysis_performed") or self.ignore_event_map: + mtzin = "refine.mtz " + else: + mtzin = "refine.mtz " + xtal + ".free.mtz " + for event in self.eventList: + mtzin += event + " " + + pdb_extract_init = ( + "source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n" + "sf_convert" + ) + + Cmd = ( + pdb_extract_init + " -o mmcif" + " -sf %s" % mtzin + + " -out {0!s}_sf.mmcif > {1!s}.sf_mmcif.log".format(xtal, xtal) + ) + + self.Logfile.insert(xtal + ": running sf_convert: " + Cmd) + os.system(Cmd) + os.system( + "/bin/rm sf_format_guess.text mtzdmp.log" + " SF_4_validate.cif sf_information.cif" + ) + + self.update_sf_mmcif_file(xtal) + + if ( + os.path.isfile(xtal + "_sf.mmcif") + and os.path.getsize(xtal + "_sf.mmcif") > 20000 + ): + self.Logfile.insert("%s: SF mmcif file successfully created" % xtal) + if self.ground_state: + self.db.execute_statement( + "update depositTable set mmCIF_SF_file='{0!s}_sf.mmcif'" + " where CrystalName is '{1!s}'" + " and DimplePANDDApath is '{2!s}'".format( + xtal, xtal, self.panddaDir + ) + ) + else: + self.db.execute_statement( + "update depositTable set mmCIF_SF_file='{0!s}_sf.mmcif'" + " where CrystalName is '{1!s}'".format(xtal, xtal) + ) + fileStatus = True + else: + self.Logfile.error("%s: SF mmcif file was not created successfully") + self.add_to_errorList(xtal) + + return fileStatus + + def apo_mmcif_exists(self): + fileStatus = False + self.Logfile.insert("checking if mmcif files of apo structures exist") + counter = 0 + for mmcif in glob.glob( + os.path.join(self.panddaDir, "processed_datasets", "*", "*.mmcif") + ): + if os.path.isfile(mmcif): + counter += 1 + if counter < 40: + self.Logfile.error("found only %s apo mmcif files" % str(counter)) + self.Logfile.warning('you may need to run "PanDDA tab"/"apo -> mmcif"') + else: + self.Logfile.insert("found %s apo mmcif files; seems OK!" % str(counter)) + fileStatus = True + return fileStatus + + def add_apo_sf_mmcif_to_ground_state_mmcif(self): + os.chdir(self.projectDir) + self.Logfile.insert( + "checking pandda directory for apo mmcif files: " + self.panddaDir + ) + f = open("ground_state_sf.mmcif", "w") + + refXtal = self.ground_state_pdb.split("/")[ + len(self.ground_state_pdb.split("/")) - 2 + ] + # make sure that mmcof belonging to ref PDB file is first + xtalList = [refXtal] + for dirs in glob.glob(os.path.join(self.panddaDir, "processed_datasets", "*")): + xtal = dirs[dirs.rfind("/") + 1 :] + if xtal not in xtalList: + xtalList.append(xtal) + + counter = 1 + for xtal in xtalList: + # this is needed in case single files are in processed_datasets + if not os.path.isdir( + os.path.join(self.panddaDir, "processed_datasets", xtal) + ): + continue + else: + dirs = os.path.join(self.panddaDir, "processed_datasets", xtal) + self.Logfile.insert( + "%s: reading saoked compound information from database" % xtal + ) + xtalDict = self.db.get_db_dict_for_sample(xtal) + if xtalDict["CompoundSMILES"].lower().replace(" ", "") == "": + smiles = "none" + elif "none" in xtalDict["CompoundSMILES"].lower().replace(" ", ""): + smiles = "none" + elif "null" in xtalDict["CompoundSMILES"].lower().replace(" ", ""): + smiles = "none" + else: + smiles = xtalDict["CompoundSMILES"].replace(" ", "") + self.Logfile.insert("%s: compound SMILES -> %s" % (xtal, smiles)) + if os.path.isfile(os.path.join(dirs, xtal + "_sf.mmcif")): + self.Logfile.insert( + "adding %s_sf.mmcif to ground-state_sf.mmcif" % xtal + ) + for line in open(os.path.join(dirs, xtal + "_sf.mmcif")): + if line.startswith("_cell.angle_gamma"): + newLine = line + newLine += "#\n" + newLine += "_diffrn.id 1\n" + newLine += ( + '_diffrn.details "diffraction data' + ' from crystal %s; soaked compound: %s"\n' + % (str(counter), smiles.replace("\n", "").replace("\r", "")) + ) + f.write(newLine) + counter += 1 + else: + f.write(line) + f.close() + self.Logfile.insert( + "added %s apo mmcif files to ground-state mmcif" % str(counter) + ) + return True + + def add_data_increment_to_apo_mmcif(self, xtal): + self.Logfile.insert("inrementing data_rxxxxsf in ground-state_sf.mmcif") + x = [ + "", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + ] + a = 0 + b = 0 + c = 0 + + foundFirstLine = False + datasetCounter = 0 + if os.path.isfile(os.path.join(self.panddaDir, "ground_state_sf.mmcif")): + f = open("ground_state_sf_tmp.mmcif", "w") + for n, line in enumerate( + open(os.path.join(self.panddaDir, "ground_state_sf.mmcif")) + ): + if line.startswith("data_rxxxxsf") and not foundFirstLine: + foundFirstLine = True + a += 1 + f.write(line) + elif line.startswith("data_rxxxxsf") and foundFirstLine: + if a == len(x): + a = 1 + b += 1 + if b == len(x): + a = 1 + b = 1 + c += 1 + newLine = line.replace("xsf", "s%ssf" % str(x[a] + x[b] + x[c])) + datasetCounter += 1 + f.write(newLine) + a += 1 + self.Logfile.insert( + "new dataset block: %s -> %s" + % ( + str(datasetCounter), + newLine.replace("\n", "").replace("\r", ""), + ) + ) + else: + f.write(line) + f.close() + os.chdir(self.panddaDir) + os.system("/bin/mv ground_state_sf_tmp.mmcif ground_state_sf.mmcif") + + if ( + os.path.isfile("ground_state_sf.mmcif") + and os.path.getsize("ground_state_sf.mmcif") > 20000 + ): + self.Logfile.insert("ground_state: SF mmcif file successfully created") + self.db.execute_statement( + "update depositTable set mmCIF_SF_file='ground_state_sf.mmcif'" + " where CrystalName is 'ground_state'" + " and DimplePANDDApath is '{0!s}'".format(self.panddaDir) + ) + else: + self.Logfile.error("%s: SF mmcif file was not created successfully") + self.add_to_errorList(xtal) + + return True + + def event_maps_exist_in_sf_mmcif(self, xtal): + fileOK = False + # set to -2 since first two data blocks are initial/final.mtz and data.mtz + n_eventMTZ_found = -2 + if os.path.isfile("no_pandda_analysis_performed") or self.ignore_event_map: + self.Logfile.warning( + "%s: no pandda analysis performed; skipping this step..." % xtal + ) + fileOK = True + else: + for line in open(xtal + "_sf.mmcif"): + if line.startswith("_refln.crystal_id"): + n_eventMTZ_found += 1 + if n_eventMTZ_found == len(self.eventList): + fileOK = True + self.Logfile.insert( + "%s: %s_sf.mmcif should contains %s of %s event maps" + % (xtal, xtal, n_eventMTZ_found, len(self.eventList)) + ) + else: + self.Logfile.error( + "%s: %s_sf.mmcif should contains only %s of %s event maps" + % (xtal, xtal, n_eventMTZ_found, len(self.eventList)) + ) + self.add_to_errorList(xtal) + return fileOK + + def update_sf_mmcif_file(self, xtal): + self.Logfile.insert("%s: updating %s_sf.mmcif" % (xtal, xtal)) + + if self.ground_state: + bound = ["data for PanDDA ground-state-mean-map"] + else: + bound = [ + "data from final refinement with ligand, final.mtz", + "data from original reflections, data.mtz", + "data for ligand evidence map (PanDDA event map), event_map_$.mtz", + ] + + block = -1 + + self.Logfile.insert( + "%s: reading wavelength from mtz file; lambda = %s" + % (xtal, str(self.data_template_dict["radiation_wavelengths"])) + ) + + if os.path.isfile("no_pandda_analysis_performed") or self.ignore_event_map: + self.Logfile.warning( + "%s: apparently not a pandda deposition; will skip this step..." % xtal + ) + return None + + for i, line in enumerate(fileinput.input(xtal + "_sf.mmcif", inplace=1)): + if line.startswith("_cell.length_a"): + block += 1 + + if line.startswith("_cell.angle_gamma"): + if block >= 2: + n = 2 + else: + n = block + sys.stdout.write(line) + newLines = ( + "#\n" + "_diffrn.id 1\n" + '_diffrn.details "%s"\n' % bound[n] + ).replace("$", str(block - 1)) + sys.stdout.write(newLines) + elif line.startswith("_diffrn_radiation_wavelength.wavelength"): + sys.stdout.write( + "_diffrn_radiation_wavelength.wavelength {0!s}\n".format( + str(self.data_template_dict["radiation_wavelengths"]) + ) + ) + else: + sys.stdout.write(line) + + +class prepare_for_group_deposition_upload(QtCore.QThread): + def __init__(self, database, xce_logfile, depositDir, projectDir, type): + QtCore.QThread.__init__(self) + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source(database) + self.depositDir = depositDir + self.projectDir = projectDir + self.type = type + + def run(self): + TextIndex = "" + os.chdir(self.depositDir) + + # ligand bound structures + if self.type == "ligand_bound": + self.Logfile.insert( + "checking depositionTable for mmcif files of ligand-bound structures" + ) + depositList = self.db.execute_statement( + "select CrystalName from mainTable where RefinementOutcome like '5%';" + ) + xtalString = "(" + for item in depositList: + xtal = str(item[0]) + self.Logfile.insert( + "%s: adding mmcif files to final tar.bz2 file" % xtal + ) + xtalString += "CrystalName = '" + xtal + "' or " + xtalString = xtalString[:-4] + ")" + toDeposit = self.db.execute_statement( + "select CrystalName,mmCIF_model_file,mmCIF_SF_file,DimplePANDDApath" + " from depositTable where StructureType is 'ligand_bound' and %s;" + % xtalString + ) + elif self.type == "ground_state": + self.Logfile.insert( + "checking depositionTable for mmcif files of ground-state structures" + ) + toDeposit = self.db.execute_statement( + "select CrystalName,mmCIF_model_file,mmCIF_SF_file,DimplePANDDApath" + " from depositTable where StructureType is 'ground_state';" + ) + else: + return + + for n, item in enumerate(sorted(toDeposit)): + xtal = str(item[0]) + if self.type == "ligand_bound": + mmcif = os.path.join(self.projectDir, xtal, str(item[1])) + mmcif_sf = os.path.join(self.projectDir, xtal, str(item[2])) + elif self.type == "ground_state": + mmcif = os.path.join(str(item[3]), str(item[1])) + mmcif_sf = os.path.join(str(item[3]), str(item[2])) + else: + continue + self.Logfile.insert("%s: %s/ %s" % (xtal, mmcif, mmcif_sf)) + if os.path.isfile(mmcif) and os.path.isfile(mmcif_sf): + self.Logfile.insert( + "copying {0!s} to {1!s}".format(mmcif, self.depositDir) + ) + os.system("/bin/cp {0!s} .".format(mmcif)) + if self.type == "ground_state": + os.system( + "/bin/mv ground_state.mmcif ground_state_{0!s}.mmcif".format( + str(n) + ) + ) + mmcif = mmcif.replace( + "ground_state.mmcif", "ground_state_{0!s}.mmcif".format(str(n)) + ) + self.Logfile.insert( + "copying {0!s} to {1!s}".format(mmcif_sf, self.depositDir) + ) + os.system("/bin/cp {0!s} .".format(mmcif_sf)) + if self.type == "ground_state": + os.system( + "/bin/mv ground_state_sf.mmcif" + " ground_state_{0!s}_sf.mmcif".format(str(n)) + ) + mmcif_sf = mmcif_sf.replace( + "ground_state_sf.mmcif", + "ground_state_{0!s}_sf.mmcif".format(str(n)), + ) + else: + self.Logfile.error("cannot find mmcif file for " + xtal) + + text = ( + "label: {0!s}-{1!s}\n".format(xtal, self.type) + + "description: {0!s} structure of {1!s}\n".format(self.type, xtal) + + "model: {0!s}\n".format(mmcif[mmcif.rfind("/") + 1 :]) + + "sf: {0!s}\n\n".format(mmcif_sf[mmcif_sf.rfind("/") + 1 :]) + ) + TextIndex += text + + f = open("index.txt", "w") + f.write(TextIndex) + f.close() + + # checking of tar.bz2 files exisit + fileList = [] + for i in sorted(glob.glob("%s_structures.tar.bz2.*" % self.type)): + fileList.append(int(i[i.rfind(".") + 1 :])) + + if os.path.isfile("%s_structures.tar.bz2" % self.type): + if fileList == []: + self.Logfile.warning( + "moving existing %s_structures.tar.bz2 to %s_structures.tar.bz2.1" + % (self.type, self.type) + ) + os.system( + "/bin/mv %s_structures.tar.bz2 %s_structures.tar.bz2.1" + % (self.type, self.type) + ) + else: + self.Logfile.warning( + "moving existing %s_structures.tar.bz2 %s_structures.tar.bz2.%s" + % (self.type, self.type, str(max(fileList) + 1)) + ) + os.system( + "/bin/mv %s_structures.tar.bz2 %s_structures.tar.bz2.%s" + % (self.type, self.type, str(max(fileList) + 1)) + ) + + self.Logfile.insert("preparing tar archive...") + os.system("tar -cvf {0!s}_structures.tar *mmcif index.txt".format(self.type)) + self.Logfile.insert("bzipping archive...") + os.system("bzip2 {0!s}_structures.tar".format(self.type)) + self.Logfile.insert( + "removing all bound mmcif files and index.txt file from " + self.depositDir + ) + os.system("/bin/rm -f *mmcif index.txt") + self.Logfile.insert("done!") + + +class import_PDB_IDs(QtCore.QThread): + def __init__(self, pdbCodes, database, xce_logfile): + QtCore.QThread.__init__(self) + self.pdbCodes = pdbCodes + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source(database) + + def run(self): + for line in self.pdbCodes.split("\n"): + if len(line.split("/")) == 2 and "-ligand_bound" in line: + xtal = line[: line.rfind("-ligand_bound")].replace(" ", "") + pdbID = line.split("/")[1].replace(" ", "") + self.Logfile.insert("setting PDB ID for " + xtal + " to " + pdbID) + sqlite = ( + "UPDATE mainTable SET Deposition_PDB_ID='{0!s}'," + "RefinementOutcome='6 - Deposited'" + " where CrystalName is '{1!s}';".format(pdbID, xtal) + ) + self.db.execute_statement(sqlite) + + +class compare_smiles_in_db_with_ligand_in_pdb(QtCore.QThread): + def __init__(self, projectDir, database, xce_logfile): + QtCore.QThread.__init__(self) + self.projectDir = projectDir + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source(database) + self.ErrorDict = {} + + def update_ErrorDict(self, xtal, message): + if xtal not in self.ErrorDict: + self.ErrorDict[xtal] = [] + self.ErrorDict[xtal].append(message) + + def run(self): + os.chdir(self.projectDir) + + progress_step = 1 + if len(glob.glob("*")) != 0: + progress_step = 100 / float(len(glob.glob("*"))) + else: + progress_step = 1 + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + for xtal in sorted(glob.glob("*")): + if os.path.isfile(os.path.join(xtal, "refine.pdb")): + smiles = self.db.execute_statement( + "select CompoundSmiles,CompoundCode from mainTable" + " where CrystalName is '{0!s}'".format(xtal) + ) + try: + LigandSmiles = str(smiles[0][0]) + LigandCode = str(smiles[0][1]) + elementDict_smiles = XChemUtils.smilestools( + LigandSmiles + ).ElementDict() + except IndexError: + self.Logfile.error( + "{0!s}: something is seems to be wrong" + " with the CompoundCode or SMILES string: {1!s}".format( + xtal, str(smiles) + ) + ) + continue + + pdb = XChemUtils.pdbtools(os.path.join(xtal, "refine.pdb")) + ligandList = pdb.ligand_details_as_list() + for ligand in ligandList: + resname = ligand[0] + chainID = ligand[1] + resseq = ligand[2] + altLoc = ligand[3] + elementDict_ligand = pdb.ElementDict( + resname, chainID, resseq, altLoc + ) + for element in elementDict_ligand: + if elementDict_ligand[element] != elementDict_smiles[element]: + self.Logfile.error( + "{0!s}: {1!s} {2!s} {3!s} {4!s} contains different" + " number of atoms than smiles in DB:" + " {5!s} -> {6!s}".format( + xtal, + resname, + chainID, + resseq, + altLoc, + LigandSmiles, + LigandCode, + ) + ) + self.update_ErrorDict( + xtal, + "{0!s} {1!s} {2!s} {3!s} contains different" + " number of atoms than smiles in DB".format( + resname, chainID, resseq, altLoc + ), + ) + break + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.emit(QtCore.SIGNAL("show_error_dict"), self.ErrorDict) diff --git a/xce/lib/XChemDialogs.py b/xce/lib/XChemDialogs.py new file mode 100755 index 00000000..6d206182 --- /dev/null +++ b/xce/lib/XChemDialogs.py @@ -0,0 +1,44 @@ +from PyQt4 import QtCore, QtGui + +from xce.lib import XChemDB + + +class select_columns_to_show(QtGui.QDialog): + def __init__(self, data_source_file, parent=None): + super(select_columns_to_show, self).__init__(parent) + self.columns_in_data_source = XChemDB.data_source( + data_source_file + ).return_column_list() + + self.column_dict = {} + + layout = QtGui.QVBoxLayout(self) + number_of_entries = len(self.columns_in_data_source) + columns_shown_in_dialog_column = 25 + grid = QtGui.QGridLayout() + x = 0 + y = 0 + columns_to_ignore = ["Sample ID", "ID"] + for entries_added in range(number_of_entries): + if not self.columns_in_data_source[entries_added][1] in columns_to_ignore: + data_source_column = QtGui.QCheckBox( + self.columns_in_data_source[entries_added][1] + ) + self.column_dict[entries_added] = data_source_column + # data_source_column.toggle() + grid.addWidget(data_source_column, y, x) + y += 1 + if y == columns_shown_in_dialog_column: + y = 0 + x += 1 + layout.addLayout(grid) + + # OK and Cancel buttons + buttons = QtGui.QDialogButtonBox( + QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel, + QtCore.Qt.Horizontal, + self, + ) + buttons.accepted.connect(self.accept) + buttons.rejected.connect(self.reject) + layout.addWidget(buttons) diff --git a/xce/lib/XChemLog.py b/xce/lib/XChemLog.py new file mode 100755 index 00000000..9428699f --- /dev/null +++ b/xce/lib/XChemLog.py @@ -0,0 +1,71 @@ +import os +from datetime import datetime + + +class startLog: + def __init__(self, logfile): + self.logfile = logfile + + def create_logfile(self, version): + pasteVersion = version + for i in range(0, 20 - len(version)): + pasteVersion += " " + + message = ( + "\n\n" + " ###################################################################\n" + " # #\n" + " # XCHEMEXPLORER - multi dataset analysis #\n" + " # #\n" + " # Version: %s #\n" + " # #\n" + " # Date: 01/08/2024 #\n" + " # #\n" + " ###################################################################\n" + "\n" % pasteVersion + ) + + if not os.path.isfile(self.logfile): + os.system("touch " + self.logfile) + message += ( + "creating new logfile for the current XChemExplorer (" + + version + + ") session:\n" + + self.logfile + + "\n" + ) + + else: + message += ( + "writing into existing logfile for current XChemExplorer (" + + version + + ") session:\n" + + self.logfile + + "\n" + ) + updateLog(self.logfile).insert(message) + + +class updateLog: + def __init__(self, logfile): + self.logfile = open(logfile, "a") + + def insert(self, message): + present_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S.%f")[:-4] + self.logfile.write(str(present_time) + " ==> XCE: " + message) + print("==> XCE: " + message) + + def warning(self, message): + present_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S.%f")[:-4] + self.logfile.write(str(present_time) + " ==> XCE: WARNING! " + message) + print("==> XCE: WARNING! " + message) + + def error(self, message): + present_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S.%f")[:-4] + self.logfile.write(str(present_time) + " ==> XCE: ERROR!!! " + message) + print("==> XCE: ERROR!!! " + message) + + def hint(self, message): + present_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S.%f")[:-4] + self.logfile.write(str(present_time) + " ==> XCE: HINT -> " + message) + print("==> XCE: HINT -> " + message) diff --git a/xce/lib/XChemMain.py b/xce/lib/XChemMain.py new file mode 100755 index 00000000..c0a5d253 --- /dev/null +++ b/xce/lib/XChemMain.py @@ -0,0 +1,1133 @@ +import glob +import gzip +import os +from datetime import datetime + +from xce.lib import XChemDB +from xce.lib import XChemLog +from xce.lib.cluster import slurm + + +def space_group_list(): + space_group_list = [ + "P1", + "P2", + "P21", + "C121", + "P1211", + "P121", + "I2", + "I121", + "P222", + "P2122", + "P2212", + "P2221", + "P21212", + "P21221", + "P22121", + "P212121", + "C222", + "C2221", + "F222", + "I222", + "I212121", + "P4", + "P41", + "P42", + "P43", + "I4", + "I41", + "P422", + "P4212", + "P4122", + "P41212", + "P4222", + "P42212", + "P4322", + "P43212", + "I422", + "I4122", + "P3", + "P31", + "P32", + "P312", + "P321", + "P3112", + "P3121", + "P3212", + "P3221", + "P6", + "P61", + "P65", + "P62", + "P64", + "P63", + "P622", + "P6122", + "P6522", + "P6222", + "P6422", + "P6322", + "H3", + "H32", + "P23", + "F23", + "I23", + "P213", + "I213", + "P432", + "P4232", + "F432", + "F4132", + "I432", + "P4332", + "P4132", + "I4132", + ] + return space_group_list + + +def get_target_and_visit_list(beamline_directory, agamemnon): + target_list = ["=== SELECT TARGET ===", "=== project directory ==="] + visit_list = [] + # the beamline directory could be a the real directory or + # a directory where the visits are linked into + if ( + len(beamline_directory.split("/")) + and beamline_directory.split("/")[1] == "dls" + and beamline_directory.split("/")[3] == "data" + and "labxchem" not in beamline_directory + ): + visit_list.append(beamline_directory) + else: + visit_list.append(os.path.realpath(beamline_directory)) + + for visit in visit_list: + print("-->", os.path.join(visit, "processed", "*")) + if agamemnon: + for target in glob.glob(os.path.join(visit, "processed", "auto", "*")): + print(target) + if target[target.rfind("/") + 1 :] not in [ + "results", + "README-log", + "edna-latest.html", + ]: + if target[target.rfind("/") + 1 :] not in target_list: + target_list.append(target[target.rfind("/") + 1 :]) + else: + for target in glob.glob(os.path.join(visit, "processed", "*")): + print(target) + if target[target.rfind("/") + 1 :] not in [ + "results", + "README-log", + "edna-latest.html", + ]: + if target[target.rfind("/") + 1 :] not in target_list: + target_list.append(target[target.rfind("/") + 1 :]) + return target_list, visit_list + + +def get_jobs_running_on_cluster(external_software, xce_logfile, token): + out_dict = {} + + dimple_jobs = [] + acedrg_jobs = [] + pandda_jobs = [] + refmac_jobs = [] + xia2_jobs = [] + others_jobs = [] + + running_jobs = slurm.query_running_jobs(xce_logfile, token) + + for job_id, job_name, job_status, run_time in running_jobs: + run_time_minutes = int(run_time.total_seconds() / 60) + + ########################################################## + # determine run time of each job in minutes + if "dimple" in job_name: + dimple_jobs.append([job_id, job_status, run_time_minutes]) + elif "acedrg" in job_name: + acedrg_jobs.append([job_id, job_status, run_time_minutes]) + elif "pandda" in job_name: + pandda_jobs.append([job_id, job_status, run_time_minutes]) + elif "refmac" in job_name: + refmac_jobs.append([job_id, job_status, run_time_minutes]) + elif "xia2" in job_name: + xia2_jobs.append([job_id, job_status, run_time_minutes]) + else: + others_jobs.append([job_id, job_status, run_time_minutes]) + + out_dict["dimple"] = dimple_jobs + out_dict["acedrg"] = acedrg_jobs + out_dict["pandda"] = pandda_jobs + out_dict["refmac"] = refmac_jobs + out_dict["xia2"] = xia2_jobs + out_dict["others"] = others_jobs + + return out_dict + + +def print_acedrg_status(xce_logfile, xtal_db_dict): + Logfile = XChemLog.updateLog(xce_logfile) + Logfile.insert("compound restraints summary:") + pending = 0 + started = 0 + running = 0 + missing_smiles = 0 + failed = 0 + success = 0 + unknown = 0 + for xtal in xtal_db_dict: + db_dict = xtal_db_dict[xtal] + status = db_dict["RefinementCIFStatus"] + if "pending" in status: + pending += 1 + elif "started" in status: + started += 1 + elif "running" in status: + running += 1 + elif "missing" in status: + missing_smiles += 1 + elif "failed" in status: + failed += 1 + elif "generated" in status: + success += 1 + else: + unknown += 1 + Logfile.insert("restraint generation pending: ...... {0!s}".format(str(pending))) + Logfile.insert("restraint generation started: ...... {0!s}".format(str(started))) + Logfile.insert("restraint generation running: ...... {0!s}".format(str(running))) + Logfile.insert( + "missing smiles string: ............. {0!s}".format(str(missing_smiles)) + ) + Logfile.insert("restraint generation failed: ....... {0!s}".format(str(failed))) + Logfile.insert("restraints successfully created: ... {0!s}".format(str(success))) + Logfile.insert("unknown status: .................... {0!s}".format(str(unknown))) + + +def print_cluster_status_message(program, cluster_dict, xce_logfile): + Logfile = XChemLog.updateLog(xce_logfile) + Logfile.insert("cluster status summary:") + Logfile.insert( + "{0!s} {1!s} jobs are running on the cluster".format( + len(cluster_dict[program]), program + ) + ) + if len(cluster_dict[program]) > 0: + cumulative_runtime = 0 + job_ids = [] + for n, item in enumerate(cluster_dict[program]): + cumulative_runtime += item[2] + if not item[0] in job_ids: + job_ids.append(item[0]) + average_runtime = round(float(cumulative_runtime) / float(n + 1), 0) + Logfile.insert("average run time " + str(average_runtime) + " minutes") + if job_ids: + Logfile.insert( + "you can kill them by pasting the following line" + " into a new terminal window:" + ) + out = "qdel " + for job in job_ids: + out += str(job) + " " + Logfile.insert(out) + + +def get_datasource_summary(db_file): + db = XChemDB.data_source(db_file) + + out_dict = {} + + out_dict["nr_samples"] = len( + db.execute_statement( + "select CrystalName from mainTable where CrystalName is not NULL;" + ) + ) + out_dict["nr_samples_failed_to_mount"] = len( + db.execute_statement( + "select HarvestStatus from mainTable where HarvestStatus is 'fail';" + ) + ) + + out_dict["nr_smiles_for_samples"] = len( + db.execute_statement( + "select compoundSMILES from mainTable" + " where compoundSMILES is not (NULL or '')" + ) + ) + + out_dict["nr_data_collection_success"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable" + " where DataCollectionOutcome is 'success';" + ) + ) + out_dict["nr_data_collection_centring_fail"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable" + " where DataCollectionOutcome is 'Failed - centring failed';" + ) + ) + out_dict["nr_data_collection_no-diffraction"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable" + " where DataCollectionOutcome is 'Failed - no diffraction';" + ) + ) + out_dict["nr_data_collection_processing_fail"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable" + " where DataCollectionOutcome is 'Failed - processing';" + ) + ) + out_dict["nr_data_collection_loop-empty"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable" + " where DataCollectionOutcome is 'Failed - loop empty';" + ) + ) + out_dict["nr_data_collection_loop-broken"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable where" + " DataCollectionOutcome is 'Failed - loop broken';" + ) + ) + out_dict["nr_data_collection_low-resolution"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable where" + " DataCollectionOutcome is 'Failed - low resolution';" + ) + ) + out_dict["nr_data_collection_no-X-rays"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable where" + " DataCollectionOutcome is 'Failed - no X-rays';" + ) + ) + out_dict["nr_data_collection_unknown"] = len( + db.execute_statement( + "select DataCollectionOutcome from mainTable where" + " DataCollectionOutcome is 'Failed - unknown';" + ) + ) + + out_dict["nr_data_collection_failed"] = ( + out_dict["nr_data_collection_centring_fail"] + + out_dict["nr_data_collection_no-diffraction"] + + out_dict["nr_data_collection_processing_fail"] + + out_dict["nr_data_collection_loop-empty"] + + out_dict["nr_data_collection_loop-broken"] + + out_dict["nr_data_collection_low-resolution"] + + out_dict["nr_data_collection_no-X-rays"] + + out_dict["nr_data_collection_unknown"] + ) + + out_dict["nr_data_collection_pending"] = ( + out_dict["nr_samples"] + - out_dict["nr_data_collection_success"] + - out_dict["nr_data_collection_centring_fail"] + - out_dict["nr_data_collection_no-diffraction"] + - out_dict["nr_data_collection_processing_fail"] + - out_dict["nr_data_collection_loop-empty"] + - out_dict["nr_data_collection_loop-broken"] + - out_dict["nr_data_collection_low-resolution"] + - out_dict["nr_data_collection_no-X-rays"] + - out_dict["nr_data_collection_unknown"] + ) + + out_dict["nr_initial_maps_available"] = len( + db.execute_statement( + "select DimplePathToMTZ from mainTable where DimplePathToMTZ is not '';" + ) + ) + out_dict["nr_initial_maps_fail"] = len( + db.execute_statement( + "select DataProcessingDimpleSuccessful from mainTable" + " where DataProcessingDimpleSuccessful = 'False';" + ) + ) + out_dict["nr_initial_maps_pending"] = ( + out_dict["nr_data_collection_success"] + - out_dict["nr_initial_maps_available"] + - out_dict["nr_initial_maps_fail"] + ) + + out_dict["nr_pandda_hits"] = len( + db.execute_statement( + "select DimplePANDDAhit from mainTable where DimplePANDDAhit = 'True';" + ) + ) + out_dict["nr_pandda_reject"] = len( + db.execute_statement( + "select DimplePANDDAreject from mainTable" + " where DimplePANDDAreject = 'True';" + ) + ) + out_dict["nr_pandda_processed"] = ( + len( + db.execute_statement( + "select DimplePANDDAwasRun from mainTable" + " where DimplePANDDAwasRun = 'True';" + ) + ) + - out_dict["nr_pandda_hits"] + - out_dict["nr_pandda_reject"] + ) + out_dict["nr_pandda_pending"] = ( + out_dict["nr_initial_maps_available"] + - out_dict["nr_pandda_hits"] + - out_dict["nr_pandda_reject"] + - out_dict["nr_pandda_processed"] + ) + + out_dict["nr_cif_files"] = len( + db.execute_statement( + "select RefinementCIF from mainTable" + " where RefinementCIF is not (Null or '');" + ) + ) + + out_dict["nr_analysis-pending"] = len( + db.execute_statement( + "select RefinementOutcome from mainTable" + " where RefinementOutcome is '1 - Analysis Pending';" + ) + ) + out_dict["nr_pandda-models"] = len( + db.execute_statement( + "select RefinementOutcome from mainTable" + " where RefinementOutcome is '2 - PANDDA model';" + ) + ) + out_dict["nr_in-refinement"] = len( + db.execute_statement( + "select RefinementOutcome from mainTable" + " where RefinementOutcome is '3 - In Refinement';" + ) + ) + out_dict["nr_comp-chem-ready"] = len( + db.execute_statement( + "select RefinementOutcome from mainTable" + " where RefinementOutcome is '4 - ComChem ready';" + ) + ) + out_dict["nr_deposition-ready"] = len( + db.execute_statement( + "select RefinementOutcome from mainTable" + " where RefinementOutcome is '5 - Deposition ready';" + ) + ) + + return out_dict + + +def change_links_to_selected_data_collection_outcome( + sample, + data_collection_dict, + data_collection_column_three_dict, + dataset_outcome_dict, + initial_model_directory, + data_source_file, + xce_logfile, +): + Logfile = XChemLog.updateLog(xce_logfile) + # find out which row was selected in respective data collection table + selected_processing_result = "n/a" + indexes = ( + data_collection_column_three_dict[sample][0].selectionModel().selectedRows() + ) + if indexes: # i.e. logfile exists + for index in sorted(indexes): + selected_processing_result = index.row() + + for n, entry in enumerate(data_collection_dict[sample]): + if entry[0] == "logfile": + if entry[7] == selected_processing_result: + visit = entry[1] + run = entry[2] + autoproc = entry[4] + db_dict = entry[6] + path_to_logfile = db_dict["DataProcessingPathToLogfile"] + path_to_mtzfile = db_dict["DataProcessingPathToMTZfile"] + mtz_filename = db_dict["DataProcessingMTZfileName"] + log_filename = db_dict["DataProcessingLOGfileName"] + # relative_path_to_mtzfile='./'+path_to_mtzfile.replace(initial_model_directory,'') + relative_path_to_mtzfile = "./" + path_to_mtzfile.replace( + os.path.join(initial_model_directory, sample), "" + ) + if relative_path_to_mtzfile.startswith(".//"): + relative_path_to_mtzfile = relative_path_to_mtzfile.replace( + ".//", "./" + ) + relative_path_to_logfile = "./" + path_to_logfile.replace( + os.path.join(initial_model_directory, sample), "" + ) + if relative_path_to_logfile.startswith(".//"): + relative_path_to_logfile = relative_path_to_logfile.replace( + ".//", "./" + ) + + # first check if folders and files exist + # since user might do this before data are actually copied over + + if os.path.isdir( + os.path.join( + initial_model_directory, + sample, + "autoprocessing", + visit + "-" + run + autoproc, + ) + ): + db_dict["DataProcessingAutoAssigned"] = "False" + Logfile.insert( + "changing directory to: " + + os.path.join(initial_model_directory, sample) + ) + os.chdir(os.path.join(initial_model_directory, sample)) + # first remove old links + os.system("/bin/rm " + sample + ".mtz 2> /dev/null") + os.system("/bin/rm " + sample + ".log 2> /dev/null") + # make new links + Logfile.insert( + "setting relative symlink: " + + os.path.join(relative_path_to_logfile, log_filename) + + " -> " + + sample + + ".log" + ) + os.symlink( + os.path.join(relative_path_to_logfile, log_filename), + sample + ".log", + ) + Logfile.insert( + "setting relative symlink: " + + os.path.join(relative_path_to_mtzfile, mtz_filename) + + " -> " + + sample + + ".mtz" + ) + os.symlink( + os.path.join(relative_path_to_mtzfile, mtz_filename), + sample + ".mtz", + ) + + # update data source + data_source = XChemDB.data_source(data_source_file) + data_source.update_insert_data_source(sample, db_dict) + + else: + Logfile.insert("please copy data to PROJECT DIRECTORY first!") + + +def get_gda_barcodes( + sampleList, gzipped_logs_parsed, gda_log_start_line, beamline, xce_logfile +): + Logfile = XChemLog.updateLog(xce_logfile) + Logfile.insert( + "checking GDA logfile in {0!s}".format( + os.path.join("/dls_sw", beamline, "logs") + ) + ) + pinDict = {} + found_barcode_entry = False + for gdaLogFile in glob.glob( + os.path.join("/dls_sw", beamline, "logs", "gda-server*log*") + ): + if gdaLogFile.endswith("tmp"): + Logfile.warning("ignoring temporary file " + gdaLogFile) + continue + Logfile.insert("parsing {0!s}".format(gdaLogFile)) + if gzipped_logs_parsed and gdaLogFile.endswith(".gz"): + Logfile.insert( + "{0!s} was already parsed during this visit".format(gdaLogFile) + ) + continue + if gdaLogFile.endswith(".gz"): + try: + with gzip.open(gdaLogFile, "r") as f: + for line in f: + if "BART SampleChanger - getBarcode() returning" in line: + barcode = line.split()[len(line.split()) - 1] + found_barcode_entry = True + if found_barcode_entry: + if "Snapshots will be saved" in line: + sampleID = line.split()[len(line.split()) - 1].split( + "/" + )[-1] + if sampleID in sampleList: + pinDict[sampleID] = barcode + Logfile.insert( + "found: sample={0!s}, barcode={1!s}," + " file={2!s}".format( + sampleID, barcode, gdaLogFile + ) + ) + found_barcode_entry = False + except IOError: + Logfile.warning("cannot open file %s" % gdaLogFile) + else: + try: + for n, line in enumerate( + open(gdaLogFile).readlines()[gda_log_start_line:] + ): + if "BART SampleChanger - getBarcode() returning" in line: + barcode = line.split()[len(line.split()) - 1] + found_barcode_entry = True + if found_barcode_entry: + if "Snapshots will be saved" in line: + sampleID = line.split()[len(line.split()) - 1].split("/")[ + -1 + ] + if sampleID in sampleList: + pinDict[sampleID] = barcode + Logfile.insert( + "found: sample={0!s}, barcode={1!s}," + " file={2!s}".format(sampleID, barcode, gdaLogFile) + ) + found_barcode_entry = False + except IOError: + Logfile.error("IOError -> " + gdaLogFile) + + try: + gda_log_start_line = gda_log_start_line + n - 1 + except UnboundLocalError: + gda_log_start_line = gda_log_start_line + + return pinDict, gda_log_start_line + + +def linkAutoProcessingResult(xtal, dbDict, projectDir, xce_logfile): + Logfile = XChemLog.updateLog(xce_logfile) + + run = dbDict["DataCollectionRun"] + subDir = dbDict["DataCollectionSubdir"] + if subDir != "": + procCode = "_" + subDir + else: + procCode = "" + visit = dbDict["DataCollectionVisit"] + autoproc = dbDict["DataProcessingProgram"] + mtzFileAbs = dbDict["DataProcessingPathToMTZfile"] + mtzfile = mtzFileAbs[mtzFileAbs.rfind("/") + 1 :] + logFileAbs = dbDict["DataProcessingPathToLogfile"] + logfile = logFileAbs[logFileAbs.rfind("/") + 1 :] + + Logfile.insert("changing directory to " + os.path.join(projectDir, xtal)) + os.chdir(os.path.join(projectDir, xtal)) + + # MTZ file + Logfile.warning("removing %s.mtz" % xtal) + os.system("/bin/rm %s.mtz" % xtal) + Logfile.insert( + xtal + + ": looking for " + + os.path.join( + "autoprocessing", visit + "-" + run + autoproc + procCode, mtzfile + ) + ) + if os.path.isfile( + os.path.join("autoprocessing", visit + "-" + run + autoproc + procCode, mtzfile) + ): + os.symlink( + os.path.join( + "autoprocessing", visit + "-" + run + autoproc + procCode, mtzfile + ), + xtal + ".mtz", + ) + Logfile.insert("linking MTZ file from different auto-processing pipeline:") + Logfile.insert( + "ln -s " + + os.path.join( + "autoprocessing", visit + "-" + run + autoproc + procCode, mtzfile + ) + + " " + + xtal + + ".mtz" + ) + # LOG file + Logfile.warning("removing %s.log" % xtal) + os.system("/bin/rm %s.log" % xtal) + Logfile.insert( + xtal + + ": looking for " + + os.path.join( + "autoprocessing", visit + "-" + run + autoproc + procCode, logfile + ) + ) + if os.path.isfile( + os.path.join("autoprocessing", visit + "-" + run + autoproc + procCode, logfile) + ): + os.symlink( + os.path.join( + "autoprocessing", visit + "-" + run + autoproc + procCode, logfile + ), + xtal + ".log", + ) + Logfile.insert("linking LOG file from different auto-processing pipeline:") + Logfile.insert( + "ln -s " + + os.path.join( + "autoprocessing", visit + "-" + run + autoproc + procCode, logfile + ) + + " " + + xtal + + ".log" + ) + + +def getProgressSteps(iterations): + if iterations == 0: + progress_step = 1 + else: + progress_step = 100 / float(iterations) + return progress_step + + +def getVisitAndBeamline(visitDirectory): + visit = "unknown" + beamline = "unknown" + if "attic" in visitDirectory: + try: + visit = visitDirectory.split("/")[6] + beamline = visitDirectory.split("/")[3] + except IndexError: + pass + else: + try: + visit = visitDirectory.split("/")[5] + beamline = visitDirectory.split("/")[2] + except IndexError: + pass + if not visitDirectory.startswith("/dls"): + # this is all a bit of a fudge in case someone transfers a DLS visit directory + # back home does most certainly not catch all possible scenarios + if visitDirectory.split("/")[len(visitDirectory.split("/")) - 2] == "processed": + visit = visitDirectory.split("/")[len(visitDirectory.split("/")) - 3] + else: + visit = visitDirectory.split("/")[len(visitDirectory.split("/")) - 1] + beamline = "unknown" + return visit, beamline + + +def crystal_growth_methods(): + methods = [ + "VAPOR DIFFUSION, SITTING DROP", + "VAPOR DIFFUSION, HANGING DROP", + "BATCH MODE", + "LIPIDIC CUBIC PHASE", + "MICROBATCH", + "MICROFLUIDIC", + ] + + return methods + + +def wwBeamlines(): + beamlines = [ + "DIAMOND BEAMLINE I02", + "DIAMOND BEAMLINE I03", + "DIAMOND BEAMLINE I04", + "DIAMOND BEAMLINE I04-1", + "DIAMOND BEAMLINE I23", + "DIAMOND BEAMLINE I24", + ] + + return beamlines + + +def radiationSource(): + source = ["SYNCHROTRON", "ROTATING ANODE", "SEALED TUBE"] + + return source + + +def detector(): + detectorPrinciple = ["PIXEL", "CCD", "IMAGE PLATE", "CMOS"] + + return detectorPrinciple + + +def detectorType(): + detector = [ + "DECTRIS PILATUS 2M", + "DECTRIS PILATUS 2M-F", + "DECTRIS PILATUS 6M", + "DECTRIS PILATUS 6M-F", + "DECTRIS PILATUS 12M", + "DECTRIS PILATUS3 2M", + "DECTRIS PILATUS3 6M", + "DECTRIS EIGER X 9M", + "DECTRIS EIGER 2XE 9M", + "DECTRIS EIGER X 16M", + "ADSC QUANTUM 315", + "ADSC QUANTUM 315r", + ] + + return detector + + +def NCBI_taxonomy_ID(): + taxonomy_dict = { + "9606": "Homo sapiens", + "10090": "Mus musculus", + "7108": "SPODOPTERA FRUGIPERDA", + "5693 ": "Trypanosoma cruzi", + "1508227": "BAT SARS-LIKE CORONAVIRUS", + "2697049": "SARS-CoV-2", + "562": "Escherichia coli", + "837": "Porphyromonas gingivalis", + "42789": "Human Enterovirus D68", + "103922": "Human Enterovirus A71", + "1335626": "MERS-CoV", + "64320": "Zika Virus", + "11060": "Dengue Virus", + "1968826": "West Nile Virus", + "37124": "Chikungunya Virus", + "31704": "Coxsackievirus A16", + } + + return taxonomy_dict + + +def data_integration_software(): + software = ["XDS", "HKL", "DENZO", "DTREK", "MOSFLM"] + + return software + + +def phasing_software(): + software = [ + "REFMAC", + "PHENIX", + "SOLVE", + "PHASER", + "CNS", + "XPLOR", + "MLPHARE", + "SHELX", + "SNB", + "BnP", + "BP3", + "SHARP", + "PHASES", + "WARP", + ] + + return software + + +def pdbx_keywords(): + keywords = [ + "", + "ALLERGEN", + "ANTIBIOTIC", + "ANTIFREEZE PROTEIN", + "ANTIFUNGAL PROTEIN", + "ANTIMICROBIAL PROTEIN", + "ANTITOXIN", + "ANTITUMOR PROTEIN", + "ANTIVIRAL PROTEIN", + "APOPTOSIS", + "ATTRACTANT", + "BIOSYNTHETIC PROTEIN", + "BLOOD CLOTTING", + "CARBOHYDRATE", + "CELL ADHESION", + "CELL CYCLE", + "CELL INVASION", + "CHAPERONE", + "CHOLINE - BINDING PROTEIN", + "CIRCADIAN CLOCK PROTEIN", + "CONTRACTILE PROTEIN", + "CYTOKINE", + "CYTOSOLIC PROTEIN", + "DE NOVO PROTEIN", + "DNA", + "DNA BINDING PROTEIN", + "DNA - RNA HYBRID", + "ELECTRON TRANSPORT", + "ENDOCYTOSIS", + "EXOCYTOSIS", + "FLAVOPROTEIN", + "FLUORESCENT PROTEIN", + "GENE REGULATION", + "HORMONE", + "HYDROLASE", + "IMMUNE SYSTEM", + "IMMUNOSUPPRESSANT", + "ISOMERASE", + "LIGASE", + "LIPID BINDING PROTEIN", + "LIPID TRANSPORT", + "LUMINESCENT PROTEIN", + "LYASE", + "MEMBRANE PROTEIN", + "METAL BINDING PROTEIN", + "METAL TRANSPORT", + "MOTOR PROTEIN", + "NEUROPEPTIDE", + "NUCLEAR PROTEIN", + "ONCOPROTEIN", + "OXIDOREDUCTASE", + "OXYGEN BINDING", + "OXYGEN STORAGE", + "OXYGEN TRANSPORT", + "PEPTIDE BINDING PROTEIN", + "PHOTOSYNTHESIS", + "PLANT PROTEIN", + "PROTEIN BINDING", + "PROTEIN FIBRIL", + "PROTEIN TRANSPORT", + "PROTON TRANSPORT", + "RECOMBINATION", + "REPLICATION", + "RIBOSOMAL PROTEIN", + "RIBOSOME", + "RNA", + "RNA BINDING PROTEIN", + "SIGNALING PROTEIN", + "SPLICING", + "STRUCTURAL GENOMICS", + "STRUCTURAL PROTEIN", + "SUGAR BINDING PROTEIN", + "SURFACTANT PROTEIN", + "TOXIN", + "TRANSCRIPTION", + "TRANSFERASE", + "TRANSLATION", + "TRANSLOCASE", + "TRANSPORT PROTEIN", + "UNKNOWN FUNCTION", + "VIRAL PROTEIN", + "VIRUS", + "VIRUS LIKE PARTICLE", + ] + + return keywords + + +def pdbx_country(): + countries = [ + "United Kingdom", + "United States", + "Japan", + "Albania", + "Andorra", + "Argentina", + "Armenia", + "Australia", + "Austria", + "Azerbaijan", + "Bahamas", + "Bangladesh", + "Barbados", + "Belarus", + "Belgium", + "Brazil", + "Bulgaria", + "Canada", + "Chile", + "China", + "Croatia", + "Cuba", + "Cyprus", + "Czech Republic", + "Denmark", + "Estonia", + "Finland", + "France", + "Germany", + "Greece", + "Hungary", + "Iceland", + "India", + "Indonesia", + "Iran, Islamic Republic Of", + "Iraq", + "Ireland", + "Israel", + "Italy", + "Jamaica", + "Jordan", + "Kazakhstan", + "Kenya", + "Kiribati", + "Korea, Republic Of", + "Latvia", + "Lithuania", + "Luxembourg", + "Malta", + "Mexico", + "Netherlands", + "New Zealand", + "Norway", + "Pakistan", + "Paraguay", + "Peru", + "Philippines", + "Poland", + "Portugal", + "Romania", + "Russian Federation", + "Serbia", + "Singapore", + "Slovakia", + "Slovenia", + "South Africa", + "Spain", + "Sweden", + "Switzerland", + "Taiwan", + "Thailand", + "Turkey", + "Ukraine", + "United Arab Emirates", + "Uruguay", + ] + return countries + + +def read_html(file_name): + source_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "html_fragments", + file_name + ".html", + ) + with open(source_path) as file: + return file.read() + + +def html_header(): + return read_html("header") + + +def html_ngl(firstPDB, firstEvent, firstMap, firstDiffMap, ligID): + ligChain = ligID.split("-")[1] + ligResid = ligID.split("-")[2] + + return read_html("ngl") % ( + firstPDB, + firstEvent, + firstMap, + firstDiffMap, + ligChain, + ligResid, + ) + + +def html_download(protein_name): + return read_html("download") % ( + protein_name, + protein_name, + protein_name, + protein_name, + protein_name, + ) + + +def html_guide(): + return read_html("guide") + + +def html_table_header(): + return read_html("table_header") + + +def html_table_row( + xtalID, + pdbID, + ligID, + compoundImage, + residuePlot, + pdb, + event, + thumbNail, + resoHigh, + spg, + unitCell, + FWT, + DELFWT, + ligConfidence, + modelStatus, +): + ligChain = ligID.split("-")[1] + ligResid = ligID.split("-")[2] + + return read_html("table_row") % ( + xtalID, + pdbID, + pdbID, + ligID, + ligConfidence, + modelStatus, + compoundImage, + residuePlot, + pdbID, + pdb, + event, + FWT, + DELFWT, + ligChain, + ligResid, + thumbNail, + resoHigh, + spg, + unitCell, + pdb.replace(".pdb", ""), + ligID, + ) + + +def html_footer(): + return read_html("footer") + + +def coot_prepare_input(x, y, z, ligID, sampleDir, eventMap): + os.chdir(sampleDir) + cmd = ( + "# !/usr/bin/env coot\n" + "# python script for coot - generated by dimple\n" + "import coot\n" + 'set_nomenclature_errors_on_read("ignore")\n' + 'molecule = read_pdb("refine.split.bound-state.pdb")\n' + "set_rotation_centre(%s, %s, %s)\n" % (x, y, z) + "set_zoom(30.)\n" + "set_view_quaternion(-0.180532, -0.678828, 0, 0.711759)\n" + 'coot.handle_read_ccp4_map(("%s"),0)\n' % eventMap + + 'coot.raster3d("%s.r3d")\n' % ligID + + "coot_real_exit(0)\n" + ) + f = open(ligID + ".py", "w") + f.write(cmd) + f.close() + + +def coot_write_raster_file(ligID, sampleDir): + os.chdir(sampleDir) + os.system("coot --no-graphics --no-guano --script %s.py" % ligID) + + +def render_scene(xtal, ligID, sampleDir): + os.chdir(sampleDir) + os.system("render < %s.r3d -png %s_%s.png" % (ligID, xtal, ligID)) + + +def make_thumbnail(xtal, ligID, sampleDir): + os.chdir(sampleDir) + os.system( + "convert -thumbnail 150x150 %s_%s.png %s_%s_thumb.png" + % (xtal, ligID, xtal, ligID) + ) + + +def backup_soakDB(database, xce_logfile): + Logfile = XChemLog.updateLog(xce_logfile) + Logfile.insert( + "backing up soakDB: " + database + str(datetime.now()).replace(" ", "_") + ) + os.system( + "/bin/cp %s %s" + % ( + database, + database + "." + str(datetime.now()).replace(" ", "_").replace(":", "-"), + ) + ) diff --git a/xce/lib/XChemPANDDA.py b/xce/lib/XChemPANDDA.py new file mode 100755 index 00000000..a9efb87f --- /dev/null +++ b/xce/lib/XChemPANDDA.py @@ -0,0 +1,2060 @@ +import csv +import glob +import os +from datetime import datetime +import subprocess + +from PyQt4 import QtCore + +from xce.lib import XChemDB +from xce.lib import XChemLog +from xce.lib import XChemRefine +from xce.lib import XChemToolTips +from xce.lib import XChemUtils +from xce.lib.cluster import slurm + +try: + import gemmi + import pandas +except ImportError: + pass + + +class export_and_refine_ligand_bound_models(QtCore.QThread): + def __init__( + self, + PanDDA_directory, + datasource, + project_directory, + xce_logfile, + which_models, + slurm_token, + ): + QtCore.QThread.__init__(self) + self.PanDDA_directory = PanDDA_directory + self.datasource = datasource + self.db = XChemDB.data_source(self.datasource) + self.Logfile = XChemLog.updateLog(xce_logfile) + self.xce_logfile = xce_logfile + self.project_directory = project_directory + self.which_models = which_models + self.slurm_token = slurm_token + self.external_software = XChemUtils.external_software(xce_logfile).check() + + def run(self): + self.Logfile.warning( + XChemToolTips.pandda_export_ligand_bound_models_only_disclaimer() + ) + + # find pandda_inspect_events.csv and read in as pandas dataframe + inspect_csv = None + if os.path.isfile( + os.path.join(self.PanDDA_directory, "analyses", "pandda_inspect_events.csv") + ): + inspect_csv = pandas.read_csv( + os.path.join( + self.PanDDA_directory, "analyses", "pandda_inspect_events.csv" + ) + ) + + # find all folders with *-pandda-model.pdb + modelsDict = self.find_modeled_structures_and_timestamps(inspect_csv) + + # if only NEW models shall be exported, check timestamps + if not self.which_models.startswith("all"): + modelsDict = self.find_new_models(modelsDict) + + progress = 0 + try: + progress_step = float(1 / len(modelsDict)) + except TypeError: + self.Logfile.error("DID NOT FIND ANY MODELS TO EXPORT") + return None + + for xtal in sorted(modelsDict): + os.chdir(os.path.join(self.PanDDA_directory, "processed_datasets", xtal)) + pandda_model = os.path.join( + "modelled_structures", xtal + "-pandda-model.pdb" + ) + pdb = gemmi.read_structure(pandda_model) + + # find out ligand event map relationship + ligandDict = XChemUtils.pdbtools_gemmi( + pandda_model + ).center_of_mass_ligand_dict("LIG") + if ligandDict == {}: + self.Logfile.error( + xtal + ": cannot find ligand of type LIG; skipping..." + ) + continue + self.show_ligands_in_model(xtal, ligandDict) + emapLigandDict = self.find_ligands_matching_event_map( + inspect_csv, xtal, ligandDict + ) + + self.Logfile.warning("emapLigandDict" + str(emapLigandDict)) + + # convert event map to SF + self.event_map_to_sf(pdb.resolution, emapLigandDict) + + # move existing event maps in project directory to old folder + self.move_old_event_to_backup_folder(xtal) + + # copy event MTZ to project directory + self.copy_event_mtz_to_project_directory(xtal) + + # copy pandda-model to project directory + self.copy_pandda_model_to_project_directory(xtal) + + # make map from MTZ and cut around ligand + self.make_and_cut_map(xtal, emapLigandDict) + + # update database + self.update_database(xtal, modelsDict) + + # refine models + self.refine_exported_model(xtal) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + def update_database(self, xtal, modelsDict): + db_dict = {} + timestamp_file = modelsDict[xtal] + db_dict["DatePanDDAModelCreated"] = timestamp_file + db_dict["RefinementOutcome"] = "3 - In Refinement" + self.Logfile.insert( + "updating database for " + + xtal + + " setting time model was created to " + + db_dict["DatePanDDAModelCreated"] + ) + self.db.update_data_source(xtal, db_dict) + + def make_and_cut_map(self, xtal, emapLigandDict): + self.Logfile.insert( + "changing directory to " + os.path.join(self.project_directory, xtal) + ) + os.chdir(os.path.join(self.project_directory, xtal)) + XChemUtils.pdbtools_gemmi(xtal + "-pandda-model.pdb").save_ligands_to_pdb("LIG") + for ligID in emapLigandDict: + m = emapLigandDict[ligID] + emtz = m.replace(".ccp4", "_" + ligID + ".mtz") + emap = m.replace(".ccp4", "_" + ligID + ".ccp4") + XChemUtils.maptools().calculate_map(emtz, "FWT", "PHWT") + XChemUtils.maptools().cut_map_around_ligand(emap, ligID + ".pdb", "7") + if os.path.isfile(emap.replace(".ccp4", "_mapmask.ccp4")): + os.system( + "/bin/mv %s %s_%s_event.ccp4" + % (emap.replace(".ccp4", "_mapmask.ccp4"), xtal, ligID) + ) + os.system( + "ln -s %s_%s_event.ccp4 %s_%s_event_cut.ccp4" + % (xtal, ligID, xtal, ligID) + ) + + def copy_pandda_model_to_project_directory(self, xtal): + os.chdir(os.path.join(self.project_directory, xtal)) + model = os.path.join( + self.PanDDA_directory, + "processed_datasets", + xtal, + "modelled_structures", + xtal + "-pandda-model.pdb", + ) + self.Logfile.insert("copying %s to project directory" % model) + os.system("/bin/cp %s ." % model) + + def copy_event_mtz_to_project_directory(self, xtal): + self.Logfile.insert( + "changing directory to " + + os.path.join(self.PanDDA_directory, "processed_datasets", xtal) + ) + os.chdir(os.path.join(self.PanDDA_directory, "processed_datasets", xtal)) + for emap in glob.glob("*-BDC_*.mtz"): + self.Logfile.insert( + "copying %s to %s..." + % (emap, os.path.join(self.project_directory, xtal)) + ) + os.system( + "/bin/cp %s %s" % (emap, os.path.join(self.project_directory, xtal)) + ) + + def move_old_event_to_backup_folder(self, xtal): + self.Logfile.insert( + "changing directory to " + os.path.join(self.project_directory, xtal) + ) + os.chdir(os.path.join(self.project_directory, xtal)) + if not os.path.isdir("event_map_backup"): + os.mkdir("event_map_backup") + self.Logfile.insert("moving existing event maps to event_map_backup") + for emap in glob.glob("*-BDC_*.ccp4"): + os.system( + "/bin/mv %s event_map_backup/%s" + % ( + emap, + emap + + "." + + str(datetime.now()).replace(" ", "_").replace(":", "-"), + ) + ) + + def show_ligands_in_model(self, xtal, ligandDict): + self.Logfile.insert(xtal + ": found the following ligands...") + for lig in ligandDict: + self.Logfile.insert(lig + " -> coordinates " + str(ligandDict[lig])) + + def find_modeled_structures_and_timestamps(self, pandda_inspect_table): + self.Logfile.insert( + "finding out modelled structures in " + self.PanDDA_directory + ) + modelsDict = {} + for model in sorted( + glob.glob( + os.path.join( + self.PanDDA_directory, + "processed_datasets", + "*", + "modelled_structures", + "*-pandda-model.pdb", + ) + ) + ): + sample = model[model.rfind("/") + 1 :].replace("-pandda-model.pdb", "") + + # Check if dataset has a corresponding plausible event and skip if not + dtag_table = pandda_inspect_table[pandda_inspect_table["dtag"] == sample] + non_low_confidence_table = dtag_table[ + dtag_table["Ligand Placed"] == True # noqa: E712 + ] + if len(non_low_confidence_table) == 0: + self.Logfile.insert(sample + " has no fitted events. Skipping!") + continue + + timestamp = datetime.fromtimestamp(os.path.getmtime(model)).strftime( + "%Y-%m-%d %H:%M:%S" + ) + self.Logfile.insert( + sample + "-pandda-model.pdb was created on " + str(timestamp) + ) + modelsDict[sample] = timestamp + return modelsDict + + def find_new_models(self, modelsDict): + samples_to_export = {} + self.Logfile.hint( + 'XCE will never export/ refine models that are "5-deposition ready" or' + ' "6-deposited"' + ) + self.Logfile.hint( + "Please change the RefinementOutcome flag in the Refinement table" + " if you wish to re-export them" + ) + self.Logfile.insert("checking timestamps of models in database...") + for xtal in modelsDict: + timestamp_file = modelsDict[xtal] + db_query = self.db.execute_statement( + "select DatePanDDAModelCreated from mainTable where CrystalName is '" + + xtal + + "' and (RefinementOutcome like '3%' or RefinementOutcome like '4%')" + ) + try: + timestamp_db = str(db_query[0][0]) + except IndexError: + self.Logfile.warning( + "%s: database query gave no results for DatePanDDAModelCreated;" + " skipping..." % xtal + ) + self.Logfile.warning( + "%s: this might be a brand new model; will continue with export!" + % xtal + ) + samples_to_export[xtal] = timestamp_file + # some time in the future... + timestamp_db = "2100-01-01 00:00:00" + try: + difference = datetime.strptime( + timestamp_file, "%Y-%m-%d %H:%M:%S" + ) - datetime.strptime(timestamp_db, "%Y-%m-%d %H:%M:%S") + if difference.seconds != 0: + self.Logfile.insert( + "exporting " + + xtal + + " -> was already refined, but newer PanDDA model available" + ) + samples_to_export[xtal] = timestamp_file + else: + self.Logfile.insert( + "%s: model has not changed since it was created on %s" + % (xtal, timestamp_db) + ) + except (ValueError, IndexError) as e: + self.Logfile.error(str(e)) + return samples_to_export + + def event_map_to_sf(self, resolution, emapLigandDict): + for lig in emapLigandDict: + emap = emapLigandDict[lig] + emtz = emap.replace(".ccp4", ".mtz") + emtz_ligand = emap.replace(".ccp4", "_" + lig + ".mtz") + self.Logfile.insert( + "trying to convert %s to SF -> %s" % (emap, emtz_ligand) + ) + self.Logfile.insert(">>> " + emtz) + XChemUtils.maptools_gemmi(emap).map_to_sf(resolution) + if os.path.isfile(emtz): + os.system("/bin/mv %s %s" % (emtz, emtz_ligand)) + self.Logfile.insert("success; %s exists" % emtz_ligand) + else: + self.Logfile.warning( + "something went wrong; %s could not be created..." % emtz_ligand + ) + + def find_ligands_matching_event_map(self, inspect_csv, xtal, ligandDict): + emapLigandDict = {} + for index, row in inspect_csv.iterrows(): + if row["dtag"] == xtal: + for emap in glob.glob("*-BDC_*.ccp4"): + self.Logfile.insert( + "checking if event and ligand are within 7A of each other" + ) + x = float(row["x"]) + y = float(row["y"]) + z = float(row["z"]) + matching_ligand = self.calculate_distance_to_ligands( + ligandDict, x, y, z + ) + if matching_ligand is not None: + emapLigandDict[matching_ligand] = emap + self.Logfile.insert( + "found matching ligand (%s) for %s" + % (matching_ligand, emap) + ) + break + else: + self.Logfile.warning("current ligand not close to event...") + if emapLigandDict == {}: + self.Logfile.error("could not find ligands within 7A of PanDDA events") + return emapLigandDict + + def calculate_distance_to_ligands(self, ligandDict, x, y, z): + matching_ligand = None + p_event = gemmi.Position(x, y, z) + for ligand in ligandDict: + c = ligandDict[ligand] + p_ligand = gemmi.Position(c[0], c[1], c[2]) + self.Logfile.insert( + "coordinates ligand: " + str(c[0]) + " " + str(c[1]) + " " + str(c[2]) + ) + self.Logfile.insert( + "coordinates event: " + str(x) + " " + str(y) + " " + str(z) + ) + distance = p_event.dist(p_ligand) + self.Logfile.insert( + "distance between ligand and event: %s A" % str(distance) + ) + if distance < 7: + matching_ligand = ligand + break + return matching_ligand + + def refine_exported_model(self, xtal): + RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + "WATER": "", + "LIGOCC": "", + "SANITY": "", + } + + if "nocheck" in self.which_models: + RefmacParams["SANITY"] = "off" + + self.Logfile.insert("trying to refine " + xtal + "...") + self.Logfile.insert("%s: getting compound code from database" % xtal) + query = self.db.execute_statement( + "select CompoundCode from mainTable where CrystalName='%s';" % xtal + ) + compoundID = str(query[0][0]) + self.Logfile.insert("%s: compounds code = %s" % (xtal, compoundID)) + if os.path.isfile( + os.path.join(self.project_directory, xtal, xtal + ".free.mtz") + ): + if os.path.isfile( + os.path.join(self.project_directory, xtal, xtal + "-pandda-model.pdb") + ): + self.Logfile.insert( + "running inital refinement on PANDDA model of " + xtal + ) + Serial = XChemRefine.GetSerial(self.project_directory, xtal) + if not os.path.isdir( + os.path.join(self.project_directory, xtal, "cootOut") + ): + os.mkdir(os.path.join(self.project_directory, xtal, "cootOut")) + # create folder for new refinement cycle + if os.path.isdir( + os.path.join( + self.project_directory, xtal, "cootOut", "Refine_" + str(Serial) + ) + ): + os.chdir( + os.path.join( + self.project_directory, + xtal, + "cootOut", + "Refine_" + str(Serial), + ) + ) + else: + os.mkdir( + os.path.join( + self.project_directory, + xtal, + "cootOut", + "Refine_" + str(Serial), + ) + ) + os.chdir( + os.path.join( + self.project_directory, + xtal, + "cootOut", + "Refine_" + str(Serial), + ) + ) + os.system( + "/bin/cp %s in.pdb" + % os.path.join( + self.project_directory, xtal, xtal + "-pandda-model.pdb" + ) + ) + Refine = XChemRefine.Refine( + self.project_directory, xtal, compoundID, self.datasource + ) + Refine.RunBuster( + str(Serial), + RefmacParams, + self.external_software, + self.xce_logfile, + None, + self.slurm_token, + ) + else: + self.Logfile.error( + "%s: cannot find %s-pandda-model.pdb; cannot start refinement..." + % (xtal, xtal) + ) + + else: + self.Logfile.error( + "%s: cannot start refinement because %s.free.mtz is missing in %s" + % (xtal, xtal, os.path.join(self.project_directory, xtal)) + ) + + +class run_pandda_export(QtCore.QThread): + def __init__( + self, + panddas_directory, + datasource, + initial_model_directory, + xce_logfile, + which_models, + pandda_params, + slurm_token, + ): + QtCore.QThread.__init__(self) + self.panddas_directory = panddas_directory + self.datasource = datasource + self.initial_model_directory = initial_model_directory + self.db = XChemDB.data_source(self.datasource) + self.db.create_missing_columns() + self.external_software = XChemUtils.external_software(xce_logfile).check() + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.which_models = which_models + self.already_exported_models = [] + self.pandda_analyse_data_table = pandda_params["pandda_table"] + self.slurm_token = slurm_token + + self.RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + } + + def update_event_map_headers(self): + base = "/dls/science/groups/i04-1/software/update_event_map_headers" + script = ( + "#!/bin/bash\n" + ". /etc/profile.d/modules.sh\n" + "{}/env/bin/python " + "{}/update_event_map_headers.py " + "{}".format(base, base, self.panddas_directory) + ) + p = subprocess.Popen( + script, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True + ) + stdout, stderr = p.communicate() + + def run(self): + self.update_event_map_headers() + + samples_to_export = self.export_models() + + self.import_samples_into_datasouce(samples_to_export) + + self.refine_exported_models(samples_to_export) + + def refine_exported_models(self, samples_to_export): + self.Logfile.insert("will try to refine the following crystals:") + for xtal in samples_to_export: + self.Logfile.insert(xtal) + for xtal in sorted(samples_to_export): + self.Logfile.insert("%s: getting compound code from database" % xtal) + query = self.db.execute_statement( + "select CompoundCode from mainTable where CrystalName='%s';" % xtal + ) + compoundID = str(query[0][0]) + self.Logfile.insert("%s: compounds code = %s" % (xtal, compoundID)) + if os.path.isfile( + os.path.join(self.initial_model_directory, xtal, xtal + ".free.mtz") + ): + if os.path.isfile( + os.path.join( + self.initial_model_directory, xtal, xtal + "-ensemble-model.pdb" + ) + ): + self.Logfile.insert( + "running inital refinement on PANDDA model of " + xtal + ) + Serial = XChemRefine.GetSerial(self.initial_model_directory, xtal) + ####################################################### + if not os.path.isdir( + os.path.join(self.initial_model_directory, xtal, "cootOut") + ): + os.mkdir( + os.path.join(self.initial_model_directory, xtal, "cootOut") + ) + # create folder for new refinement cycle + if os.path.isdir( + os.path.join( + self.initial_model_directory, + xtal, + "cootOut", + "Refine_" + str(Serial), + ) + ): + os.chdir( + os.path.join( + self.initial_model_directory, + xtal, + "cootOut", + "Refine_" + str(Serial), + ) + ) + try: + os.system("/bin/rm *-ensemble-model.pdb *restraints*") + except Exception: + self.Logfile.error( + "Restraint files didn't exist to remove." + " Will try to continue" + ) + else: + os.mkdir( + os.path.join( + self.initial_model_directory, + xtal, + "cootOut", + "Refine_" + str(Serial), + ) + ) + os.chdir( + os.path.join( + self.initial_model_directory, + xtal, + "cootOut", + "Refine_" + str(Serial), + ) + ) + Refine = XChemRefine.panddaRefine( + self.initial_model_directory, xtal, compoundID, self.datasource + ) + os.symlink( + os.path.join( + self.initial_model_directory, + xtal, + xtal + "-ensemble-model.pdb", + ), + xtal + "-ensemble-model.pdb", + ) + Refine.RunQuickRefine( + Serial, + self.RefmacParams, + self.external_software, + self.xce_logfile, + "pandda_refmac", + None, + self.slurm_token, + ) + else: + self.Logfile.error( + "%s: cannot find %s-ensemble-model.pdb;" + " cannot start refinement..." % (xtal, xtal) + ) + self.Logfile.error( + "Please check terminal window for any PanDDA related tracebacks" + ) + + elif xtal in samples_to_export and not os.path.isfile( + os.path.join(self.initial_model_directory, xtal, xtal + ".free.mtz") + ): + self.Logfile.error( + "%s: cannot start refinement because %s.free.mtz is missing in %s" + % (xtal, xtal, os.path.join(self.initial_model_directory, xtal)) + ) + else: + self.Logfile.insert("%s: nothing to refine" % (xtal)) + + def import_samples_into_datasouce(self, samples_to_export): + # first make a note of all the datasets which were used in pandda directory + os.chdir(os.path.join(self.panddas_directory, "processed_datasets")) + for xtal in glob.glob("*"): + self.db.execute_statement( + "update mainTable set DimplePANDDAwasRun = 'True'," + "DimplePANDDAreject = 'False',DimplePANDDApath='{0!s}'" + " where CrystalName is '{1!s}'".format(self.panddas_directory, xtal) + ) + # do the same as before, but look for rejected datasets + + try: + os.chdir(os.path.join(self.panddas_directory, "rejected_datasets")) + for xtal in glob.glob("*"): + self.db.execute_statement( + "update mainTable set DimplePANDDAwasRun = 'True'," + "DimplePANDDAreject = 'True',DimplePANDDApath='{0!s}'," + "DimplePANDDAhit = 'False' where CrystalName is '{1!s}'".format( + self.panddas_directory, xtal + ) + ) + except OSError: + pass + + site_list = [] + pandda_hit_list = [] + + with open( + os.path.join( + self.panddas_directory, "analyses", "pandda_inspect_sites.csv" + ), + "rb", + ) as csv_import: + csv_dict = csv.DictReader(csv_import) + self.Logfile.insert("reding pandda_inspect_sites.csv") + for i, line in enumerate(csv_dict): + self.Logfile.insert(str(line).replace("\n", "").replace("\r", "")) + site_index = line["site_idx"] + name = line["Name"].replace("'", "") + comment = line["Comment"] + site_list.append([site_index, name, comment]) + self.Logfile.insert( + "add to site_list_:" + str([site_index, name, comment]) + ) + + progress_step = 1 + for i, line in enumerate( + open( + os.path.join( + self.panddas_directory, "analyses", "pandda_inspect_events.csv" + ) + ) + ): + n_lines = i + if n_lines != 0: + progress_step = 100 / float(n_lines) + else: + progress_step = 0 + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.Logfile.insert( + "reading " + + os.path.join( + self.panddas_directory, "analyses", "pandda_inspect_events.csv" + ) + ) + with open( + os.path.join( + self.panddas_directory, "analyses", "pandda_inspect_events.csv" + ), + "rb", + ) as csv_import: + csv_dict = csv.DictReader(csv_import) + + for i, line in enumerate(csv_dict): + db_dict = {} + sampleID = line["dtag"] + if sampleID not in samples_to_export: + self.Logfile.warning( + "%s: not to be exported; will not add to panddaTable..." + % sampleID + ) + continue + if sampleID not in pandda_hit_list: + pandda_hit_list.append(sampleID) + site_index = str(line["site_idx"]).replace(".0", "") + event_index = str(line["event_idx"]).replace(".0", "") + self.Logfile.insert(str(line)) + self.Logfile.insert( + "reading {0!s} -> site {1!s} -> event {2!s}".format( + sampleID, site_index, event_index + ) + ) + + for entry in site_list: + if entry[0] == site_index: + site_name = entry[1] + site_comment = entry[2] + break + + # check if EVENT map exists in project directory + event_map = "" + for file in glob.glob( + os.path.join(self.initial_model_directory, sampleID, "*ccp4") + ): + filename = file[file.rfind("/") + 1 :] + if filename.startswith( + sampleID + "-event_" + event_index + ) and filename.endswith("map.native.ccp4"): + event_map = file + self.Logfile.insert( + "found respective event maps in {0!s}: {1!s}".format( + self.initial_model_directory, event_map + ) + ) + break + + # initial pandda model and mtz file + pandda_model = "" + for file in glob.glob( + os.path.join(self.initial_model_directory, sampleID, "*pdb") + ): + filename = file[file.rfind("/") + 1 :] + if filename.endswith("-ensemble-model.pdb"): + pandda_model = file + if sampleID not in self.already_exported_models: + self.already_exported_models.append(sampleID) + break + inital_mtz = "" + for file in glob.glob( + os.path.join(self.initial_model_directory, sampleID, "*mtz") + ): + filename = file[file.rfind("/") + 1 :] + if filename.endswith("pandda-input.mtz"): + inital_mtz = file + break + + db_dict["CrystalName"] = sampleID + db_dict["PANDDApath"] = self.panddas_directory + db_dict["PANDDA_site_index"] = site_index + db_dict["PANDDA_site_name"] = site_name + db_dict["PANDDA_site_comment"] = site_comment + db_dict["PANDDA_site_event_index"] = event_index + db_dict["PANDDA_site_event_comment"] = line["Comment"].replace("'", "") + db_dict["PANDDA_site_confidence"] = line["Ligand Confidence"] + db_dict["PANDDA_site_InspectConfidence"] = line["Ligand Confidence"] + db_dict["PANDDA_site_ligand_placed"] = line["Ligand Placed"] + db_dict["PANDDA_site_viewed"] = line["Viewed"] + db_dict["PANDDA_site_interesting"] = line["Interesting"] + db_dict["PANDDA_site_z_peak"] = line["z_peak"] + db_dict["PANDDA_site_x"] = line["x"] + db_dict["PANDDA_site_y"] = line["y"] + db_dict["PANDDA_site_z"] = line["z"] + db_dict["PANDDA_site_ligand_id"] = "" + db_dict["PANDDA_site_event_map"] = event_map + db_dict["PANDDA_site_initial_model"] = pandda_model + db_dict["PANDDA_site_initial_mtz"] = inital_mtz + db_dict["PANDDA_site_spider_plot"] = "" + + # find apo structures which were used + # XXX missing XXX + + self.db.update_insert_site_event_panddaTable(sampleID, db_dict) + + # this is necessary, otherwise RefinementOutcome will be reset for + # samples that are actually already in refinement + self.db.execute_statement( + "update panddaTable set RefinementOutcome = '2 - PANDDA model'" + " where CrystalName is '{0!s}'" + " and RefinementOutcome is null".format(sampleID) + ) + self.db.execute_statement( + "update mainTable set RefinementOutcome = '2 - PANDDA model'" + " where CrystalName is '{0!s}' and (RefinementOutcome is null" + " or RefinementOutcome is '1 - Analysis Pending')".format(sampleID) + ) + self.db.execute_statement( + "update mainTable set DimplePANDDAhit = 'True'" + " where CrystalName is '{0!s}'".format(sampleID) + ) + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.Logfile.insert("done reading pandda_inspect_sites.csv") + + # finally find all samples which do not have a pandda hit + os.chdir(os.path.join(self.panddas_directory, "processed_datasets")) + self.Logfile.insert("check which datasets are not interesting") + # DimplePANDDAhit + + def export_models(self): + self.Logfile.insert("finding out which PanDDA models need to be exported") + + # find pandda_inspect_events.csv and read in as pandas dataframe + inspect_csv = None + if os.path.isfile( + os.path.join( + self.panddas_directory, + "analyses", + "pandda_inspect_events.csv", + ) + ): + inspect_csv = pandas.read_csv( + os.path.join( + self.panddas_directory, "analyses", "pandda_inspect_events.csv" + ) + ) + + # first find which samples are in interesting datasets and have a model + # and determine the timestamp + fileModelsDict = {} + queryModels = "" + for model in glob.glob( + os.path.join( + self.panddas_directory, + "processed_datasets", + "*", + "modelled_structures", + "*-pandda-model.pdb", + ) + ): + sample = model[model.rfind("/") + 1 :].replace("-pandda-model.pdb", "") + + # Check if there are non-low confidence models + sample_events = inspect_csv[inspect_csv["dtag"] == sample] + sample_high_conf_events = sample_events[ + sample_events["Ligand Placed"] == True # noqa: E712 + ] + if len(sample_high_conf_events) == 0: + self.Logfile.insert( + "{}: Found {} fitted events! Not Exporting!".format( + sample, len(sample_high_conf_events) + ) + ) + continue + else: + self.Logfile.insert( + "{}: Found {} fitted events! Exporting!".format( + sample, len(sample_high_conf_events) + ) + ) + + timestamp = datetime.fromtimestamp(os.path.getmtime(model)).strftime( + "%Y-%m-%d %H:%M:%S" + ) + self.Logfile.insert( + sample + "-pandda-model.pdb was created on " + str(timestamp) + ) + queryModels += "'" + sample + "'," + fileModelsDict[sample] = timestamp + + # now get these models from the database and compare the datestamps + # Note: only get the models that underwent some form of refinement, + # because only if the model was updated in pandda.inspect will it be + # exported and refined + dbModelsDict = {} + if queryModels != "": + dbEntries = self.db.execute_statement( + "select CrystalName,DatePanDDAModelCreated from mainTable" + " where CrystalName in (" + + queryModels[:-1] + + ") and (RefinementOutcome like '3%' or RefinementOutcome like '4%'" + " or RefinementOutcome like '5%')" + ) + for item in dbEntries: + xtal = str(item[0]) + timestamp = str(item[1]) + dbModelsDict[xtal] = timestamp + self.Logfile.insert( + "PanDDA model for " + + xtal + + " is in database and was created on " + + str(timestamp) + ) + + # compare timestamps and only export the ones where the timestamp of the file + # is newer than the one in the DB + samples_to_export = {} + self.Logfile.insert( + "checking which PanDDA models were newly created or updated" + ) + if self.which_models == "all": + self.Logfile.insert("Note: you chose to export ALL available PanDDA!") + + for sample in fileModelsDict: + if self.which_models == "all": + self.Logfile.insert("exporting " + sample) + samples_to_export[sample] = fileModelsDict[sample] + elif self.which_models == "selected": + for i in range(0, self.pandda_analyse_data_table.rowCount()): + if str(self.pandda_analyse_data_table.item(i, 0).text()) == sample: + if self.pandda_analyse_data_table.cellWidget(i, 1).isChecked(): + self.Logfile.insert( + "Dataset selected by user -> exporting " + sample + ) + samples_to_export[sample] = fileModelsDict[sample] + break + else: + if sample in dbModelsDict: + try: + difference = datetime.strptime( + fileModelsDict[sample], "%Y-%m-%d %H:%M:%S" + ) - datetime.strptime(dbModelsDict[sample], "%Y-%m-%d %H:%M:%S") + if difference.seconds != 0: + self.Logfile.insert( + "exporting " + sample + " -> was already refined," + " but newer PanDDA model available" + ) + samples_to_export[sample] = fileModelsDict[sample] + except ValueError: + # this will be raised if timestamp is not properly formatted; + # which will usually be the case when respective field in + # database is blank. these are hopefully legacy cases which are + # from before this extensive check was introduced (13/01/2017) + advice = ( + "The pandda model of " + + xtal + + " was changed, but it was already refined! " + "This is most likely because this was done with an older" + " version of XCE. " + "If you really want to export and refine this model," + " you need to open the database " + "with DBbroweser (sqlitebrowser.org);" + " then change the RefinementOutcome field " + 'of the respective sample to "2 - PANDDA model","" save the' + " database and repeat the export prodedure." + ) + self.Logfile.insert(advice) + else: + self.Logfile.insert( + "exporting " + + sample + + " -> first time to be exported and refined" + ) + samples_to_export[sample] = fileModelsDict[sample] + + # update the DB: + # set timestamp to current timestamp of file and set RefinementOutcome to + # '2-pandda...' + + if samples_to_export != {}: + select_dir_string = "" + select_dir_string_new_pannda = " " + for sample in samples_to_export: + db_dict = { + "RefinementOutcome": "2 - PANDDA model", + "DatePanDDAModelCreated": samples_to_export[sample], + } + select_dir_string += "select_dir={0!s} ".format(sample) + select_dir_string_new_pannda += "{0!s} ".format(sample) + self.Logfile.insert( + "updating database for " + + sample + + " setting time model was created to " + + db_dict["DatePanDDAModelCreated"] + + " and RefinementOutcome to " + + db_dict["RefinementOutcome"] + ) + self.db.update_data_source(sample, db_dict) + + if os.path.isdir(os.path.join(self.panddas_directory, "rejected_datasets")): + Cmds = ( + "pandda.export" + " pandda_dir=%s" % self.panddas_directory + + " export_dir={0!s}".format(self.initial_model_directory) + + " {0!s}".format(select_dir_string) + + " export_ligands=False" + " generate_occupancy_groupings=True\n" + ) + + else: + Cmds = ( + "module load ccp4/7.1.018\n" + "pandda.export" + " pandda_dir=%s" % self.panddas_directory + + " export_dir={0!s}".format(self.initial_model_directory) + + " {0!s}".format(select_dir_string_new_pannda) + + " generate_restraints=True\n" + ) + + self.Logfile.insert( + "running pandda.export with the following settings:\n" + Cmds + ) + os.system(Cmds) + + return samples_to_export + + +class run_pandda_analyse(QtCore.QThread): + def __init__( + self, pandda_params, xce_logfile, datasource, external_software, slurm_token + ): + QtCore.QThread.__init__(self) + self.data_directory = pandda_params["data_dir"] + self.panddas_directory = pandda_params["out_dir"] + self.submit_mode = pandda_params["submit_mode"] + self.external_software = external_software + self.slurm_token = slurm_token + + self.pandda_analyse_data_table = pandda_params["pandda_table"] + self.nproc = pandda_params["nproc"] + self.min_build_datasets = pandda_params["min_build_datasets"] + self.pdb_style = pandda_params["pdb_style"] + self.mtz_style = pandda_params["mtz_style"] + self.sort_event = pandda_params["sort_event"] + self.number_of_datasets = pandda_params["N_datasets"] + self.max_new_datasets = pandda_params["max_new_datasets"] + self.grid_spacing = pandda_params["grid_spacing"] + self.reference_dir = pandda_params["reference_dir"] + self.filter_pdb = os.path.join(self.reference_dir, pandda_params["filter_pdb"]) + self.wilson_scaling = pandda_params["perform_diffraction_data_scaling"] + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.datasource = datasource + self.db = XChemDB.data_source(datasource) + self.appendix = pandda_params["appendix"] + self.write_mean_maps = pandda_params["write_mean_map"] + self.calc_map_by = pandda_params["average_map"] + self.select_ground_state_model = "" + projectDir = self.data_directory.replace("/*", "") + self.make_ligand_links = "$CCP4/bin/ccp4-python %s %s %s\n" % ( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "make_ligand_links_after_pandda.py", + ), + projectDir, + self.panddas_directory, + ) + + if self.appendix != "": + self.panddas_directory = os.path.join( + self.reference_dir, "pandda_" + self.appendix + ) + if os.path.isdir(self.panddas_directory): + os.system("/bin/rm -fr %s" % self.panddas_directory) + os.mkdir(self.panddas_directory) + if self.data_directory.startswith("/dls"): + self.select_ground_state_model = "module load ccp4/7.1.018\n" + self.select_ground_state_model += "$CCP4/bin/ccp4-python %s %s\n" % ( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "select_ground_state_dataset.py", + ), + self.panddas_directory, + ) + self.make_ligand_links = "" + + def run(self): + # how to run pandda.analyse on large datasets + # + # 1) Run the normal pandda command, with the new setting, e.g. + # pandda.analyse data_dirs=... max_new_datasets=500 + # This will do the analysis on the first 500 datasets and build the statistical + # maps - just as normal. + # + # 2) Run pandda with the same command: + # pandda.analyse data_dirs=... max_new_datasets=500 + # This will add 500 new datasets, and process them using the existing + # statistical maps (this will be quicker than the original analysis). + # It will then merge the results of the two analyses. + # + # 3) Repeat 2) until you don't add any "new" datasets. + # Then you can build the models as normal. + + number_of_cyles = int(self.number_of_datasets) / int(self.max_new_datasets) + # modulo gives remainder after integer division + if int(self.number_of_datasets) % int(self.max_new_datasets) != 0: + number_of_cyles += 1 + self.Logfile.insert( + "will run %s rounds of pandda.analyse" % str(number_of_cyles) + ) + + if os.path.isfile(os.path.join(self.panddas_directory, "pandda.running")): + self.Logfile.insert( + "it looks as if a pandda.analyse job is currently running in: " + + self.panddas_directory + ) + msg = ( + "there are three possibilities:\n" + "1.) choose another PANDDA directory\n" + "2.) - check if the job is really running either on the cluster (qstat)" + " or on your local machine\n" + " - if so, be patient and wait until the job has finished\n" + "3.) same as 2., but instead of waiting, kill the job" + " and remove at least the pandda.running file\n" + " (or all the contents in the directory" + " if you want to start from scratch)\n" + ) + self.Logfile.insert(msg) + return None + else: + source_file = "" + source_file += ( + 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"\n' + ) + + if os.path.isfile(self.filter_pdb + ".pdb"): + print("filter pdb located") + filter_pdb = " filter.pdb=" + self.filter_pdb + ".pdb" + print(("will use " + filter_pdb + "as a filter for pandda.analyse")) + else: + filter_pdb = "" + + os.chdir(self.panddas_directory) + + dls = "" + if self.data_directory.startswith("/dls"): + dls = ( + source_file + "\n" + "module load pymol/1.8.2.0-py2.7\n" + "module load ccp4/7.0.078\n\n" + ) + + Cmds = ( + "#!/bin/bash\n" + + ". /etc/profile.d/modules.sh\n" + + "\n" + + "\n" + + dls + + "cd " + + self.panddas_directory + + "\n" + + "\n" + ) + + ignore = [] + char = [] + zmap = [] + + for i in range(0, self.pandda_analyse_data_table.rowCount()): + ignore_all_checkbox = self.pandda_analyse_data_table.cellWidget(i, 7) + ignore_characterisation_checkbox = ( + self.pandda_analyse_data_table.cellWidget(i, 8) + ) + ignore_zmap_checkbox = self.pandda_analyse_data_table.cellWidget(i, 9) + + if ignore_all_checkbox.isChecked(): + ignore.append(str(self.pandda_analyse_data_table.item(i, 0).text())) + if ignore_characterisation_checkbox.isChecked(): + char.append(str(self.pandda_analyse_data_table.item(i, 0).text())) + if ignore_zmap_checkbox.isChecked(): + zmap.append(str(self.pandda_analyse_data_table.item(i, 0).text())) + + def append_to_ignore_string(datasets_list, append_string): + if len(datasets_list) == 0: + append_string = "" + for i in range(0, len(datasets_list)): + if i < len(datasets_list) - 1: + append_string += str(datasets_list[i] + ",") + else: + append_string += str(datasets_list[i] + '"') + print(append_string) + return append_string + + ignore_string = 'ignore_datasets="' + ignore_string = append_to_ignore_string(ignore, ignore_string) + + char_string = 'exclude_from_characterisation="' + char_string = append_to_ignore_string(char, char_string) + + zmap_string = 'exclude_from_z_map_analysis="' + zmap_string = append_to_ignore_string(zmap, zmap_string) + + for i in range(number_of_cyles): + Cmds += ( + "pandda.analyse " + + ' data_dirs="' + + self.data_directory.replace("/*", "") + + '/*"' + + ' out_dir="' + + self.panddas_directory + + '"' + " min_build_datasets=" + + self.min_build_datasets + + " max_new_datasets=" + + self.max_new_datasets + + " grid_spacing=" + + self.grid_spacing + + " cpus=" + + self.nproc + + " events.order_by=" + + self.sort_event + + filter_pdb + + " pdb_style=" + + self.pdb_style + + " mtz_style=" + + self.mtz_style + + " lig_style=/compound/*.cif" + + " apply_b_factor_scaling=" + + self.wilson_scaling + + " write_average_map=" + + self.write_mean_maps + + " average_map=" + + self.calc_map_by + + " " + + ignore_string + + " " + + char_string + + " " + + zmap_string + + " " + + "\n" + ) + + Cmds += self.select_ground_state_model + Cmds += self.make_ligand_links + Cmds += "\n" + + data_dir_string = self.data_directory.replace("/*", "") + + Cmds += str( + "find " + + data_dir_string + + '/*/compound -name "*.cif" | while read line; do echo ${line//"' + + data_dir_string + + '"/"' + + self.panddas_directory + + '/processed_datasets/"}| while read line2;' + " do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; " + "done; done;" + ) + + Cmds += "\n" + + Cmds += str( + "find " + + data_dir_string + + '/*/compound -name "*.pdb" | while read line; do echo ${line//"' + + data_dir_string + + '"/"' + + self.panddas_directory + + '/processed_datasets/"}| while read line2;' + " do cp $line ${line2//compound/ligand_files} > /dev/null 2>&1; " + "done; done;" + ) + + self.Logfile.insert( + "running pandda.analyse with the following command:\n" + Cmds + ) + + f = open("pandda.sh", "w") + f.write(Cmds) + f.close() + + self.Logfile.insert( + "trying to run pandda.analyse on " + str(self.submit_mode) + ) + + if self.submit_mode == "local machine": + self.Logfile.insert("running PANDDA on local machine") + os.system("chmod +x pandda.sh") + os.system("./pandda.sh &") + else: + slurm.submit_cluster_job( + "pandda", + "pandda.sh", + self.xce_logfile, + self.slurm_token, + exclusive=True, + tasks=self.nproc, + memory=100 * 1024, + ) + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + +class run_pandda_two_analyse(QtCore.QThread): + def __init__( + self, pandda_params, xce_logfile, datasource, external_software, slurm_token + ): + QtCore.QThread.__init__(self) + self.data_directory = pandda_params["data_dir"] + self.panddas_directory = pandda_params["out_dir"] + self.submit_mode = pandda_params["submit_mode"] + self.external_software = external_software + self.slurm_token = slurm_token + + self.pandda_analyse_data_table = pandda_params["pandda_table"] + self.nproc = pandda_params["nproc"] + self.min_build_datasets = pandda_params["min_build_datasets"] + self.pdb_style = pandda_params["pdb_style"] + self.mtz_style = pandda_params["mtz_style"] + self.sort_event = pandda_params["sort_event"] + self.number_of_datasets = pandda_params["N_datasets"] + self.max_new_datasets = pandda_params["max_new_datasets"] + self.grid_spacing = pandda_params["grid_spacing"] + self.keyword_arguments = pandda_params["keyword_arguments"] + self.reference_dir = pandda_params["reference_dir"] + self.filter_pdb = os.path.join(self.reference_dir, pandda_params["filter_pdb"]) + self.wilson_scaling = pandda_params["perform_diffraction_data_scaling"] + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.datasource = datasource + self.db = XChemDB.data_source(datasource) + self.appendix = pandda_params["appendix"] + self.write_mean_maps = pandda_params["write_mean_map"] + self.calc_map_by = pandda_params["average_map"] + self.select_ground_state_model = "" + + def run(self): + if not self.data_directory.startswith("/dls"): + self.Logfile.error("Sorry, you need to be at DLS for pandda2 to work!") + return None + + os.chdir(self.panddas_directory) + + # Get the datasets to ignore + ignore = [] + char = [] + zmap = [] + + for i in range(0, self.pandda_analyse_data_table.rowCount()): + ignore_all_checkbox = self.pandda_analyse_data_table.cellWidget(i, 7) + ignore_characterisation_checkbox = ( + self.pandda_analyse_data_table.cellWidget(i, 8) + ) + ignore_zmap_checkbox = self.pandda_analyse_data_table.cellWidget(i, 9) + + if ignore_all_checkbox.isChecked(): + ignore.append(str(self.pandda_analyse_data_table.item(i, 0).text())) + if ignore_characterisation_checkbox.isChecked(): + char.append(str(self.pandda_analyse_data_table.item(i, 0).text())) + if ignore_zmap_checkbox.isChecked(): + zmap.append(str(self.pandda_analyse_data_table.item(i, 0).text())) + + def append_to_ignore_string(datasets_list, append_string): + append_string = '{}"'.format( + ",".join( + [ + append_string, + ] + + datasets_list + ) + ) + return append_string + + ignore_string = 'ignore_datasets="' + ignore_string = append_to_ignore_string(ignore, ignore_string) + + char_string = 'exclude_from_characterisation="' + char_string = append_to_ignore_string(char, char_string) + + zmap_string = 'exclude_from_z_map_analysis="' + zmap_string = append_to_ignore_string(zmap, zmap_string) + + cmd = ( + "#!/bin/bash\n" + ". /etc/profile.d/modules.sh\n" + 'export PYTHONPATH=""\n' + "/dls/science/groups/i04-1/software/pandda_2_gemmi/pandda2" + " --data_dirs={0!s}".format(self.data_directory.replace("/*", "")) + + " --out_dir={0!s}".format(self.panddas_directory) + + ' --pdb_regex="{0!s}"'.format(self.pdb_style) + + ' --mtz_regex="{0!s}"'.format(self.mtz_style) + + " --local_cpus=36" + + " {0!s}".format(self.keyword_arguments) + ) + if len(ignore) > 0: + cmd = cmd + " {}".format(ignore_string) + if len(char) > 0: + cmd = cmd + " {}".format(char_string) + if len(zmap) > 0: + cmd = cmd + " {}".format(zmap_string) + + self.Logfile.insert( + "running pandda.analyse with the following command:\n" + cmd + ) + + f = open("pandda2.sh", "w") + f.write(cmd) + f.close() + + self.Logfile.warning("ignoring selected submission option") + + slurm.submit_cluster_job( + "pandda2", + "pandda2.sh", + self.xce_logfile, + self.slurm_token, + memory=36 * 5 * 1024, + tasks=36, + ) + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + +class giant_cluster_datasets(QtCore.QThread): + def __init__( + self, + initial_model_directory, + pandda_params, + xce_logfile, + datasource, + ): + QtCore.QThread.__init__(self) + self.panddas_directory = pandda_params["out_dir"] + self.pdb_style = pandda_params["pdb_style"] + self.mtz_style = pandda_params["mtz_style"] + self.Logfile = XChemLog.updateLog(xce_logfile) + self.initial_model_directory = initial_model_directory + self.db = XChemDB.data_source(datasource) + + def run(self): + self.emit(QtCore.SIGNAL("update_progress_bar"), 0) + + if self.pdb_style.replace(" ", "") == "": + self.Logfile.insert("PDB style is not set in pandda.analyse!") + self.Logfile.insert("cannot start pandda.analyse") + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "PDB style is not set in pandda.analyse!", + ) + return None + + if self.mtz_style.replace(" ", "") == "": + self.Logfile.insert("MTZ style is not set in pandda.analyse!") + self.Logfile.insert("cannot start pandda.analyse") + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "MTZ style is not set in pandda.analyse!", + ) + return None + + # 1.) prepare output directory + os.chdir(self.panddas_directory) + if os.path.isdir("cluster_analysis"): + self.Logfile.insert( + "removing old cluster_analysis directory in {0!s}".format( + self.panddas_directory + ) + ) + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "removing old cluster_analysis directory in {0!s}".format( + self.panddas_directory + ), + ) + os.system("/bin/rm -fr cluster_analysis 2> /dev/null") + self.Logfile.insert( + "creating cluster_analysis directory in {0!s}".format( + self.panddas_directory + ) + ) + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "creating cluster_analysis directory in {0!s}".format( + self.panddas_directory + ), + ) + os.mkdir("cluster_analysis") + self.emit(QtCore.SIGNAL("update_progress_bar"), 10) + + # 2.) go through project directory and make sure that all pdb files really exist + # broken links derail the giant.cluster_mtzs_and_pdbs script + self.Logfile.insert( + "cleaning up broken links of {0!s} and {1!s} in {2!s}".format( + self.pdb_style, self.mtz_style, self.initial_model_directory + ) + ) + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "cleaning up broken links of {0!s} and {1!s} in {2!s}".format( + self.pdb_style, self.mtz_style, self.initial_model_directory + ), + ) + os.chdir(self.initial_model_directory) + for xtal in glob.glob("*"): + if not os.path.isfile(os.path.join(xtal, self.pdb_style)): + self.Logfile.insert( + "missing {0!s} and {1!s} for {2!s}".format( + self.pdb_style, self.mtz_style, xtal + ) + ) + os.system( + "/bin/rm {0!s}/{1!s} 2> /dev/null".format(xtal, self.pdb_style) + ) + os.system( + "/bin/rm {0!s}/{1!s} 2> /dev/null".format(xtal, self.mtz_style) + ) + self.emit(QtCore.SIGNAL("update_progress_bar"), 20) + + # 3.) giant.cluster_mtzs_and_pdbs + self.Logfile.insert( + "running giant.cluster_mtzs_and_pdbs {0!s}/*/{1!s}" + " pdb_regex='{2!s}/(.*)/{3!s}'" + " out_dir='{4!s}/cluster_analysis'".format( + self.initial_model_directory, + self.pdb_style, + self.initial_model_directory, + self.pdb_style, + self.panddas_directory, + ) + ) + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "running giant.cluster_mtzs_and_pdbs", + ) + + Cmds = ( + "#!" + os.getenv("SHELL") + "\n" + "unset PYTHONPATH\n" + "module load ccp4/7.1.018\n" + "giant.datasets.cluster %s/*/%s pdb_regex='%s/(.*)/%s'" + " out_dir='%s/cluster_analysis'" + % ( + self.initial_model_directory, + self.pdb_style, + self.initial_model_directory, + self.pdb_style, + self.panddas_directory, + ) + ) + + os.system(Cmds) + self.emit(QtCore.SIGNAL("update_progress_bar"), 80) + + # 4.) analyse output + self.Logfile.insert( + "parsing {0!s}/cluster_analysis".format(self.panddas_directory) + ) + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "parsing {0!s}/cluster_analysis".format(self.panddas_directory), + ) + os.chdir("{0!s}/cluster_analysis".format(self.panddas_directory)) + cluster_dict = {} + for out_dir in sorted(glob.glob("*")): + if os.path.isdir(out_dir): + cluster_dict[out_dir] = [] + for folder in glob.glob(os.path.join(out_dir, "pdbs", "*")): + xtal = folder[folder.rfind("/") + 1 :] + cluster_dict[out_dir].append(xtal) + self.emit(QtCore.SIGNAL("update_progress_bar"), 90) + + # 5.) update datasource + self.Logfile.insert( + "updating datasource with results from giant.cluster_mtzs_and_pdbs" + ) + if cluster_dict != {}: + for key in cluster_dict: + for xtal in cluster_dict[key]: + db_dict = {"CrystalFormName": key} + self.db.update_data_source(xtal, db_dict) + + # 6.) finish + self.emit(QtCore.SIGNAL("update_progress_bar"), 100) + self.Logfile.insert("finished giant.cluster_mtzs_and_pdbs") + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + +class run_pandda_inspect_at_home(QtCore.QThread): + def __init__(self, panddaDir, xce_logfile): + QtCore.QThread.__init__(self) + self.panddaDir = panddaDir + self.Logfile = XChemLog.updateLog(xce_logfile) + + def run(self): + os.chdir(os.path.join(self.panddaDir, "processed_datasets")) + + progress_step = 1 + if len(glob.glob("*")) != 0: + progress_step = 100 / float(len(glob.glob("*"))) + else: + progress_step = 1 + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.Logfile.insert("parsing " + self.panddaDir) + for xtal in sorted(glob.glob("*")): + for files in glob.glob(xtal + "/ligand_files/*"): + if os.path.islink(files): + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "replacing symlink for {0!s} with real file".format(files), + ) + self.Logfile.insert( + "replacing symlink for {0!s} with real file".format(files) + ) + os.system( + "cp --remove-destination {0!s} {1!s}/ligand_files".format( + os.path.realpath(files), xtal + ) + ) + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + XChemToolTips.run_pandda_inspect_at_home(self.panddaDir) + + +class convert_apo_structures_to_mmcif(QtCore.QThread): + def __init__(self, panddaDir, xce_logfile): + QtCore.QThread.__init__(self) + self.panddaDir = panddaDir + self.Logfile = XChemLog.updateLog(xce_logfile) + + def sf_convert_environment(self): + return ( + "source /dls/science/groups/i04-1/software/pdb-extract-prod/setup.sh\n" + "sf_convert" + ) + + def run(self): + self.Logfile.insert( + "converting apo structures in pandda directory to mmcif files" + ) + self.Logfile.insert("chanfing to " + self.panddaDir) + progress_step = 1 + if len(glob.glob("*")) != 0: + progress_step = 100 / float( + len(glob.glob(os.path.join(self.panddaDir, "processed_datasets", "*"))) + ) + else: + progress_step = 1 + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + pdb_extract_init = self.sf_convert_environment() + + self.Logfile.insert("parsing " + self.panddaDir) + for dirs in glob.glob(os.path.join(self.panddaDir, "processed_datasets", "*")): + xtal = dirs[dirs.rfind("/") + 1 :] + self.Logfile.insert( + "%s: converting %s to mmcif" % (xtal, xtal + "-pandda-input.mtz") + ) + if os.path.isfile(os.path.join(dirs, xtal + "-pandda-input.mtz")): + if os.path.isfile(os.path.join(dirs, xtal + "_sf.mmcif")): + self.Logfile.insert( + "%s: %s_sf.mmcif exists; skipping..." % (xtal, xtal) + ) + else: + os.chdir(dirs) + Cmd = ( + pdb_extract_init + " -o mmcif" + " -sf %s" % xtal + + "-pandda-input.mtz" + + " -out {0!s}_sf.mmcif > {1!s}.sf_mmcif.log".format( + xtal, xtal + ) + ) + self.Logfile.insert("running command: " + Cmd) + os.system(Cmd) + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + +class check_number_of_modelled_ligands(QtCore.QThread): + def __init__(self, project_directory, xce_logfile, db_file): + QtCore.QThread.__init__(self) + self.Logfile = XChemLog.updateLog(xce_logfile) + self.project_directory = project_directory + self.db = XChemDB.data_source(db_file) + self.errorDict = {} + + def update_errorDict(self, xtal, message): + if xtal not in self.errorDict: + self.errorDict[xtal] = [] + self.errorDict[xtal].append(message) + + def run(self): + self.Logfile.insert("reading modelled ligands from panddaTable") + dbDict = {} + + sqlite = ( + "select " + " CrystalName," + " PANDDA_site_index," + " PANDDA_site_x," + " PANDDA_site_y," + " PANDDA_site_z," + " PANDDA_site_ligand_resname," + " PANDDA_site_ligand_chain," + " PANDDA_site_ligand_sequence_number," + " PANDDA_site_event_map," + " PANDDA_site_event_map_mtz," + " PANDDA_site_initial_model," + " PANDDA_site_initial_mtz," + " RefinementOutcome," + " PANDDA_site_event_index," + " PANDDApath " + "from panddaTable " + ) + + dbEntries = self.db.execute_statement(sqlite) + for item in dbEntries: + xtal = str(item[0]) + site = str(item[1]) + x = str(item[2]) + y = str(item[3]) + z = str(item[4]) + resname = str(item[5]) + chain = str(item[6]) + seqnum = str(item[7]) + eventMap = str(item[8]) + eventMap_mtz = str(item[9]) + initialPDB = str(item[10]) + initialMTZ = str(item[11]) + outcome = str(item[12]) + event = str(item[13]) + PanDDApath = str(item[14]) + + if xtal not in dbDict: + dbDict[xtal] = [] + dbDict[xtal].append( + [ + site, + x, + y, + z, + resname, + chain, + seqnum, + eventMap, + eventMap_mtz, + initialPDB, + initialMTZ, + outcome, + event, + PanDDApath, + ] + ) + + os.chdir(self.project_directory) + + progress_step = 1 + if len(glob.glob("*")) != 0: + progress_step = 100 / float(len(glob.glob("*"))) + else: + progress_step = 1 + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + for xtal in sorted(glob.glob("*")): + if os.path.isfile(os.path.join(xtal, "refine.pdb")): + ligands = XChemUtils.pdbtools( + os.path.join(xtal, "refine.pdb") + ).ligand_details_as_list() + self.Logfile.insert("{0!s}: found file refine.pdb".format(xtal)) + if ligands: + if os.path.isdir(os.path.join(xtal, "xceTmp")): + os.system( + "/bin/rm -fr {0!s}".format(os.path.join(xtal, "xceTmp")) + ) + os.mkdir(os.path.join(xtal, "xceTmp")) + else: + self.Logfile.warning( + "{0!s}: cannot find ligand molecule in refine.pdb;" + " skipping...".format(xtal) + ) + continue + + ligands_not_in_panddaTable = [] + for n, item in enumerate(ligands): + resnameLIG = item[0] + chainLIG = item[1] + seqnumLIG = item[2] + altLocLIG = item[3] + occupancyLig = item[4] + if altLocLIG.replace(" ", "") == "": + self.Logfile.insert( + xtal + + ": found a ligand not modelled with pandda.inspect ->" + " {0!s} {1!s} {2!s}".format(resnameLIG, chainLIG, seqnumLIG) + ) + residue_xyz = XChemUtils.pdbtools( + os.path.join(xtal, "refine.pdb") + ).get_center_of_gravity_of_residue_ish(item[1], item[2]) + ligands[n].append(residue_xyz) + foundLigand = False + if xtal in dbDict: + for entry in dbDict[xtal]: + resnameTable = entry[4] + chainTable = entry[5] + seqnumTable = entry[6] + self.Logfile.insert( + "panddaTable: {0!s} {1!s} {2!s} {3!s}".format( + xtal, resnameTable, chainTable, seqnumTable + ) + ) + if ( + resnameLIG == resnameTable + and chainLIG == chainTable + and seqnumLIG == seqnumTable + ): + self.Logfile.insert( + "{0!s}: found ligand in database ->" + " {1!s} {2!s} {3!s}".format( + xtal, resnameTable, chainTable, seqnumTable + ) + ) + foundLigand = True + if not foundLigand: + self.Logfile.error( + "{0!s}: did NOT find ligand in database ->" + " {1!s} {2!s} {3!s}".format( + xtal, resnameLIG, chainLIG, seqnumLIG + ) + ) + ligands_not_in_panddaTable.append( + [ + resnameLIG, + chainLIG, + seqnumLIG, + altLocLIG, + occupancyLig, + residue_xyz, + ] + ) + else: + self.Logfile.warning( + "ligand in PDB file, but dataset not listed in panddaTable:" + " {0!s} -> {1!s} {2!s} {3!s}".format( + xtal, item[0], item[1], item[2] + ) + ) + + for entry in ligands_not_in_panddaTable: + self.Logfile.error( + "{0!s}: refine.pdb contains a ligand that is not assigned in" + " the panddaTable: {1!s} {2!s} {3!s} {4!s}".format( + xtal, entry[0], entry[1], entry[2], entry[3] + ) + ) + + for site in ligands_not_in_panddaTable: + for files in glob.glob( + os.path.join( + self.project_directory, xtal, "xceTmp", "ligand_*_*.pdb" + ) + ): + mol_xyz = XChemUtils.pdbtools( + files + ).get_center_of_gravity_of_molecule_ish() + # now need to check if there is a unassigned entry in + # panddaTable that is close + for entry in dbDict[xtal]: + distance = ( + XChemUtils.calculate_distance_between_coordinates( + mol_xyz[0], + mol_xyz[1], + mol_xyz[2], + entry[1], + entry[2], + entry[3], + ) + ) + self.Logfile.insert( + "{0!s}: {1!s} {2!s} {3!s} <--->" + " {4!s} {5!s} {6!s}".format( + xtal, + mol_xyz[0], + mol_xyz[1], + mol_xyz[2], + entry[1], + entry[2], + entry[3], + ) + ) + self.Logfile.insert( + "{0!s}: symm equivalent molecule: {1!s}".format( + xtal, files + ) + ) + self.Logfile.insert( + "{0!s}: distance: {1!s}".format(xtal, str(distance)) + ) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + if self.errorDict != {}: + self.update_errorDict( + "General", + "The aforementioned PDB files were automatically changed by XCE!\n" + "Please check and refine them!!!", + ) + self.emit(QtCore.SIGNAL("show_error_dict"), self.errorDict) + + +class find_event_map_for_ligand(QtCore.QThread): + def __init__(self, project_directory, xce_logfile, external_software): + QtCore.QThread.__init__(self) + self.Logfile = XChemLog.updateLog(xce_logfile) + self.project_directory = project_directory + self.external_software = external_software + + def run(self): + self.Logfile.insert("======== checking ligand CC in event maps ========") + for dirs in sorted(glob.glob(os.path.join(self.project_directory, "*"))): + xtal = dirs[dirs.rfind("/") + 1 :] + if os.path.isfile(os.path.join(dirs, "refine.pdb")) and os.path.isfile( + os.path.join(dirs, "refine.mtz") + ): + self.Logfile.insert("%s: found refine.pdb" % xtal) + os.chdir(dirs) + try: + p = gemmi.read_structure("refine.pdb") + except Exception: + self.Logfile.error("gemmi library not available") + self.external_software["gemmi"] = False + reso = XChemUtils.mtztools("refine.mtz").get_dmin() + ligList = XChemUtils.pdbtools("refine.pdb").save_residues_with_resname( + dirs, "LIG" + ) + self.Logfile.insert( + "%s: found %s ligands of type LIG in refine.pdb" + % (xtal, str(len(ligList))) + ) + + for maps in glob.glob(os.path.join(dirs, "*event*.native.ccp4")): + if self.external_software["gemmi"]: + self.convert_map_to_sf_with_gemmi(maps, p) + else: + self.expand_map_to_p1(maps) + self.convert_map_to_sf(maps.replace(".ccp4", ".P1.ccp4"), reso) + + summary = "" + for lig in sorted(ligList): + if self.external_software["gemmi"]: + for mtz in sorted( + glob.glob(os.path.join(dirs, "*event*.native.mtz")) + ): + self.get_lig_cc(mtz, lig) + cc = self.check_lig_cc(mtz.replace(".mtz", "_CC.log")) + summary += "%s: %s LIG CC = %s (%s)\n" % ( + xtal, + lig, + cc, + mtz[mtz.rfind("/") + 1 :], + ) + else: + for mtz in sorted( + glob.glob(os.path.join(dirs, "*event*.native*P1.mtz")) + ): + self.get_lig_cc(mtz, lig) + cc = self.check_lig_cc(mtz.replace(".mtz", "_CC.log")) + summary += "%s: %s LIG CC = %s (%s)\n" % ( + xtal, + lig, + cc, + mtz[mtz.rfind("/") + 1 :], + ) + self.Logfile.insert( + "\nsummary of CC analysis:\n======================:\n" + summary + ) + + def expand_map_to_p1(self, emap): + self.Logfile.insert("expanding map to P1: %s" % emap) + if os.path.isfile(emap.replace(".ccp4", ".P1.ccp4")): + self.Logfile.warning("P1 map exists; skipping...") + return + cmd = ( + "mapmask MAPIN %s MAPOUT %s << eof\n" + % (emap, emap.replace(".ccp4", ".P1.ccp4")) + + " XYZLIM CELL\n" + " PAD 0.0\n" + " SYMMETRY 1\n" + "eof\n" + ) + os.system(cmd) + + def convert_map_to_sf(self, emap, reso): + self.Logfile.insert( + "converting ccp4 map to mtz with phenix.map_to_structure_factors: %s" % emap + ) + if os.path.isfile(emap.replace(".ccp4", ".mtz")): + self.Logfile.warning("mtz file of event map exists; skipping...") + return + cmd = ( + "module load phenix/1.20\n" + "phenix.map_to_structure_factors %s d_min=%s\n" + % ( + emap, + reso, + ) + + "/bin/mv map_to_structure_factors.mtz %s" % emap.replace(".ccp4", ".mtz") + ) + os.system(cmd) + + def get_lig_cc(self, mtz, lig): + self.Logfile.insert("calculating CC for %s in %s" % (lig, mtz)) + if os.path.isfile(mtz.replace(".mtz", "_CC.log")): + self.Logfile.warning("logfile of CC analysis exists; skipping...") + return + cmd = "module load phenix/1.20\n" "phenix.get_cc_mtz_pdb %s %s > %s" % ( + mtz, + lig, + mtz.replace(".mtz", "_CC.log"), + ) + os.system(cmd) + + def check_lig_cc(self, log): + cc = "n/a" + if os.path.isfile(log): + for line in open(log): + if line.startswith("local"): + cc = line.split()[len(line.split()) - 1] + else: + self.Logfile.error("logfile does not exist: %s" % log) + return cc + + def convert_map_to_sf_with_gemmi(self, emap, p): + self.Logfile.insert("converting ccp4 map to mtz with gemmi map2sf: %s" % emap) + if os.path.isfile(emap.replace(".ccp4", ".mtz")): + self.Logfile.warning("mtz file of event map exists; skipping...") + return + cmd = "gemmi map2sf %s %s FWT PHWT --dmin=%s" % ( + emap, + emap.replace(".ccp4", ".mtz"), + p.resolution, + ) + self.Logfile.insert("converting map with command:\n" + cmd) + os.system(cmd) diff --git a/xce/lib/XChemPlots.py b/xce/lib/XChemPlots.py new file mode 100755 index 00000000..9320fbcd --- /dev/null +++ b/xce/lib/XChemPlots.py @@ -0,0 +1,79 @@ +import numpy as np + +from xce.lib import XChemMain + + +class summary_plot(object): + def __init__(self, datasource, overview_axes): + self.datasource = datasource + self.overview_axes = overview_axes + + def update_overview(self): + db_dict = XChemMain.get_datasource_summary(self.datasource) + + category = ( + "Crystals mounted", + "Data Collection", + "Maps", + "PANDDA", + "Refinement", + "Comp Chem", + ) + + N = len(category) + Success = np.array( + [ + db_dict["nr_samples"], + db_dict["nr_data_collection_success"], + db_dict["nr_initial_maps_available"], + db_dict["nr_pandda_hits"], + 5, + 6, + ] + ) + + Processed = np.array([0, 0, 0, db_dict["nr_pandda_processed"], 0, 0]) + + Pending = np.array( + [ + 0, + db_dict["nr_data_collection_pending"], + db_dict["nr_initial_maps_pending"], + db_dict["nr_pandda_pending"], + 2, + 1, + ] + ) + + Failure = np.array( + [ + db_dict["nr_samples_failed_to_mount"], + db_dict["nr_data_collection_failed"], + db_dict["nr_initial_maps_fail"], + db_dict["nr_pandda_reject"], + 2, + 3, + ] + ) + + ind = np.arange(N) # the x locations for the groups + width = 0.35 # the width of the bars + + p0 = self.overview_axes.bar(ind, Success, width, color="g") + p1 = self.overview_axes.bar(ind, Processed, width, color="b", bottom=Success) + p2 = self.overview_axes.bar( + ind, Pending, width, color="y", bottom=Success + Processed + ) + p3 = self.overview_axes.bar( + ind, Failure, width, color="r", bottom=Pending + Success + Processed + ) + + # add some text for labels, title and axes ticks + self.overview_axes.set_ylabel("N") + self.overview_axes.set_title("Overview") + self.overview_axes.set_xticks(ind + width) + self.overview_axes.set_xticklabels(category) + + self.overview_axes.legend( + (p0[0], p1[0], p2[0], p3[0]), ("Success", "Processed", "Pending", "Failure") + ) diff --git a/xce/lib/XChemRefine.py b/xce/lib/XChemRefine.py new file mode 100755 index 00000000..787603c2 --- /dev/null +++ b/xce/lib/XChemRefine.py @@ -0,0 +1,2389 @@ +import getpass +import glob +import os +from datetime import datetime + +import gtk +import pygtk + +from xce.lib import XChemLog +from xce.lib import XChemUtils +from xce.lib.cluster import slurm + +pygtk.require("2.0") + + +def GetSerial(ProjectPath, xtalID): + # check if there were already previous refinements + # if no: create a folder Refine_1 + # if yes: create a folder Refine_ + temp = [] + found = 0 + if os.path.isdir(os.path.join(ProjectPath, xtalID)): + for item in glob.glob(os.path.join(ProjectPath, xtalID, "*")): + if item.startswith(os.path.join(ProjectPath, xtalID, "Refine_")): + if item.endswith("-report"): + continue + try: + temp.append(int(item[item.rfind("_") + 1 :])) + except ValueError: + continue + found = 1 + if found: + Serial = max(temp) + 1 + else: + Serial = 1 + return Serial + + +class RefineParams(object): + def __init__(self, ProjectPath, xtalID, compoundID, datasource): + self.ProjectPath = ProjectPath + self.xtalID = xtalID + self.compoundID = compoundID + self.datasource = datasource + + def RefmacRefinementParams(self, RefmacParams): + self.RefmacParams = RefmacParams + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_title("Refmac Parameters") + self.vbox = gtk.VBox() + + self.hbox1 = gtk.HBox() + self.hbox1.add(gtk.Label("Refine")) + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseBfacRefinement) + for item in ["isotropic", "anisotropic"]: + self.cb.append_text(item) + if "ISOT" in self.RefmacParams["BREF"]: + self.cb.set_active(0) + if "ANIS" in self.RefmacParams["BREF"]: + self.cb.set_active(1) + self.hbox1.add(self.cb) + self.hbox1.add(gtk.Label("temperature factors")) + self.vbox.add(self.hbox1) + + self.hbox2 = gtk.HBox() + self.hbox2.add(gtk.Label("Number of Cycles: ")) + self.Ncycles = gtk.Entry() + self.Ncycles.add_events(gtk.gdk.KEY_RELEASE_MASK) + self.Ncycles.connect("key-release-event", self.on_key_release_Ncycles) + self.Ncycles.set_text(self.RefmacParams["NCYCLES"]) + self.hbox2.add(self.Ncycles) + self.vbox.add(self.hbox2) + + self.hbox3 = gtk.HBox() + self.hbox3.add(gtk.Label("MATRIX WEIGHT: ")) + self.MATRIX_WEIGHT = gtk.Entry() + self.MATRIX_WEIGHT.add_events(gtk.gdk.KEY_RELEASE_MASK) + self.MATRIX_WEIGHT.connect( + "key-release-event", self.on_key_release_MATRIX_WEIGHT + ) + self.MATRIX_WEIGHT.set_text(self.RefmacParams["MATRIX_WEIGHT"]) + self.hbox3.add(self.MATRIX_WEIGHT) + self.vbox.add(self.hbox3) + + self.TLS = gtk.CheckButton("TLS (find TLS groups with phenix.find_tls_groups)") + self.TLS.connect("toggled", self.TLSCallback) + if self.RefmacParams["TLS"] == "refi tlsc 10\n": + self.TLS.set_active(True) + self.vbox.pack_start(self.TLS, False) + + self.NCS = gtk.CheckButton("NCS (if applicable") + self.NCS.connect("toggled", self.NCSCallback) + if self.RefmacParams["NCS"] == "NCSR LOCAL\n": + self.NCS.set_active(True) + self.vbox.pack_start(self.NCS, False) + + self.TWIN = gtk.CheckButton("Twin?") + self.TWIN.connect("toggled", self.TWINCallback) + if self.RefmacParams["TWIN"] == "TWIN\n": + self.TWIN.set_active(True) + self.vbox.pack_start(self.TWIN, False) + + self.WATER = gtk.CheckButton("Update waters (BUSTER)") + self.WATER.connect("toggled", self.WATERCallback) + if self.RefmacParams["WATER"] == "WATER\n": + self.WATER.set_active(True) + self.vbox.pack_start(self.WATER, False) + + self.LIGOCC = gtk.CheckButton("Refine ligand occupancy (BUSTER)") + self.LIGOCC.connect("toggled", self.LIGOCCCallback) + if self.RefmacParams["LIGOCC"] == "LIGOCC\n": + self.LIGOCC.set_active(True) + self.vbox.pack_start(self.LIGOCC, False) + + self.SANITY = gtk.CheckButton("Ignore sanity checks (BUSTER)") + self.SANITY.connect("toggled", self.SANITYCallback) + if self.RefmacParams["SANITY"] == "off\n": + self.SANITY.set_active(True) + self.vbox.pack_start(self.SANITY, False) + + self.OKbutton = gtk.Button(label="OK") + self.OKbutton.connect("clicked", self.OK) + self.vbox.add(self.OKbutton) + + self.window.add(self.vbox) + self.window.show_all() + return self.RefmacParams + + def TLSCallback(self, widget): + if widget.get_active(): + self.RefmacParams["TLS"] = "refi tlsc 10\n" + self.RefmacParams["TLSIN"] = "refmac.tls\n" + self.RefmacParams["TLSOUT"] = "out.tls\n" + self.RefmacParams["TLSADD"] = "TLSO ADDU\n" + else: + self.RefmacParams["TLS"] = "" + self.RefmacParams["TLSIN"] = "" + self.RefmacParams["TLSOUT"] = "" + self.RefmacParams["TLSADD"] = "" + return self.RefmacParams + + def NCSCallback(self, widget): + if widget.get_active(): + self.RefmacParams["NCS"] = "NCSR LOCAL\n" + else: + self.RefmacParams["NCS"] = "" + return self.RefmacParams + + def ChooseBfacRefinement(self, widget): + if widget.get_active_text() == "isotropic": + self.RefmacParams["BREF"] = " bref ISOT\n" + if widget.get_active_text() == "anisotropic": + self.RefmacParams["BREF"] = " bref ANIS\n" + return self.RefmacParams + + def on_key_release_Ncycles(self, widget, event): + print(widget.get_text()) + self.RefmacParams["NCYCLES"] = widget.get_text() + return self.RefmacParams + + def on_key_release_MATRIX_WEIGHT(self, widget, event): + self.RefmacParams["MATRIX_WEIGHT"] = widget.get_text() + return self.RefmacParams + + def TWINCallback(self, widget): + if widget.get_active(): + self.RefmacParams["TWIN"] = "TWIN\n" + else: + self.RefmacParams["TWIN"] = "" + return self.RefmacParams + + def WATERCallback(self, widget): + if widget.get_active(): + self.RefmacParams["WATER"] = "WATER\n" + else: + self.RefmacParams["WATER"] = "" + return self.RefmacParams + + def LIGOCCCallback(self, widget): + if widget.get_active(): + self.RefmacParams["LIGOCC"] = "LIGOCC\n" + else: + self.RefmacParams["LIGOCC"] = "" + return self.RefmacParams + + def SANITYCallback(self, widget): + if widget.get_active(): + self.RefmacParams["SANITY"] = "off\n" + else: + self.RefmacParams["SANITY"] = "" + return self.RefmacParams + + def OK(self, widget): + self.window.destroy() + + def ParamsFromPreviousCycle(self, Serial): + RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + "WATER": "", + "LIGOCC": "", + "SANITY": "", + } + + if os.path.isfile( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(Serial) + + "/refmac.csh" + ): + for line in open( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(Serial) + + "/refmac.csh" + ): + if line.startswith("refi tlsc"): + RefmacParams["TLS"] = line + if line.startswith("TLSO"): + RefmacParams["TLSADD"] = line + if line.startswith("NCSR LOCAL"): + RefmacParams["NCS"] = line + if line.startswith(" bref "): + RefmacParams["BREF"] = line + if line.startswith("ncyc"): + RefmacParams["Ncycles"] = line.split()[1] + if line.startswith("weight"): + RefmacParams["MATRIX_WEIGHT"] = line.split()[len(line.split()) - 1] + if line.startswith("TWIN"): + RefmacParams["TWIN"] = line + elif os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "refmac.csh", + ) + ): + for line in open( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "refmac.csh", + ) + ): + if line.startswith("refi tlsc"): + RefmacParams["TLS"] = line + if line.startswith("TLSO"): + RefmacParams["TLSADD"] = line + if line.startswith("NCSR LOCAL"): + RefmacParams["NCS"] = line + if line.startswith(" bref "): + RefmacParams["BREF"] = line + if line.startswith("ncyc"): + RefmacParams["Ncycles"] = line.split()[1] + if line.startswith("weight"): + RefmacParams["MATRIX_WEIGHT"] = line.split()[len(line.split()) - 1] + if line.startswith("TWIN"): + RefmacParams["TWIN"] = line + + return RefmacParams + + def GetRefinementHistory(self): + RefinementCycle = [] + RcrystList = [] + RfreeList = [] + + found = False + for item in glob.glob(os.path.join(self.ProjectPath, self.xtalID, "*")): + if item.startswith(os.path.join(self.ProjectPath, self.xtalID, "Refine_")): + print(item[item.rfind("_") + 1 :]) + RefinementCycle.append(int(item[item.rfind("_") + 1 :])) + found = True + if found: + for cycle in sorted(RefinementCycle): + try: + found_Rcryst = False + found_Rfree = False + newestPDB = max( + glob.iglob( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(cycle) + + "/refine_" + + str(cycle) + + ".pdb" + ), + key=os.path.getctime, + ) + for line in open(newestPDB): + if line.startswith( + "REMARK 3 R VALUE (WORKING + TEST SET) :" + ): + Rcryst = line.split()[9] + RcrystList.append(float(Rcryst)) + found_Rcryst = True + if line.startswith( + "REMARK 3 FREE R VALUE :" + ): + Rfree = line.split()[6] + RfreeList.append(float(Rfree)) + found_Rfree = True + if not found_Rcryst: + RcrystList.append(0) + if not found_Rfree: + RfreeList.append(0) + except ValueError: + RcrystList.append(0) + RfreeList.append(0) + else: + RefinementCycle = [0] + RcrystList = [0] + RfreeList = [0] + print(RefinementCycle, RcrystList, RfreeList) + return (sorted(RefinementCycle), RcrystList, RfreeList) + + +class Refine(object): + def __init__(self, ProjectPath, xtalID, compoundID, datasource): + self.ProjectPath = ProjectPath + self.xtalID = xtalID + self.compoundID = compoundID + self.datasource = datasource + self.error = False + self.Logfile = None + + def GetSerial(self): + # check if there were already previous refinements + # if no: create a folder Refine_1 + # if yes: create a folder Refine_ + temp = [] + found = 0 + if os.path.isdir(os.path.join(self.ProjectPath, self.xtalID)): + for item in glob.glob(os.path.join(self.ProjectPath, self.xtalID, "*")): + if item.startswith( + os.path.join(self.ProjectPath, self.xtalID, "Refine_") + ): + print(int(item[item.rfind("_") + 1 :])) + temp.append(int(item[item.rfind("_") + 1 :])) + found = 1 + if found: + Serial = max(temp) + 1 + else: + Serial = 1 + return Serial + + def make_covalent_link(self, covLinkAtomSpec, Logfile): + residuesToModify = ["CYS", "SER"] + + atom1 = covLinkAtomSpec[1][5] + atom2 = covLinkAtomSpec[2][5] + residue_1 = covLinkAtomSpec[3] + residue_2 = covLinkAtomSpec[4] + + if residue_2 in residuesToModify: + bond_text = ( + "LINK: RES-NAME-1 %s FILE-1 %s_acedrg.cif ATOM-NAME-1 %s RES-NAME-2" + " %s ATOM-NAME-2 %s" + % (residue_1, self.compoundID, atom1, residue_2, atom2) + ) + else: + bond_text = ( + "LINK: RES-NAME-1 %s FILE-1 %s_acedrg.cif ATOM-NAME-1 %s RES-NAME-2" + " %s ATOM-NAME-2 %s" + % (residue_2, self.compoundID, atom2, residue_1, atom1) + ) + + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + f = open("covalent_bond.txt", "w") + f.write(bond_text) + f.close() + + # seems somewhat unncessary, but acedrg does not like some certain descriptions + # generated by phenix.elbow + os.system("acedrg -c %s.cif -o %s_acedrg" % (self.compoundID, self.compoundID)) + + os.system("acedrg -L covalent_bond.txt -o %s" % self.compoundID) + + if os.path.isfile("%s_link.cif" % self.compoundID): + Logfile.insert("succefully created link file %s_link.cif" % self.compoundID) + os.system("/bin/rm %s.cif" % self.compoundID) + os.system("ln -s %s_link.cif %s.cif" % (self.compoundID, self.compoundID)) + else: + Logfile.error( + "could not create linkfile; please check logs in %s/%s" + % (self.ProjectPath, self.xtalID) + ) + + def get_hklin_hklout(self, Serial): + ####################################################### + # HKLIN & HKLOUT + hklin = None + hklout = None + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, self.xtalID + ".free.mtz") + ): + hklin = os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + ".free.mtz" + ) + else: + self.Logfile.error("%s: cannot find HKLIN for refinement" % self.xtalID) + self.error = True + hklout = os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + Serial, + "refine_" + Serial + ".mtz", + ) + return hklin, hklout + + def get_xyzin_xyzout(self, Serial): + ####################################################### + # XYZIN & XYZOUT + xyzin = None + xyzout = None + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, "Refine_" + Serial, "in.pdb") + ): + xyzin = os.path.join( + self.ProjectPath, self.xtalID, "Refine_" + Serial, "in.pdb" + ) + xyzout = os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + Serial, + "refine_" + Serial + ".pdb", + ) + elif os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "in.pdb", + ) + ): + xyzin = os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "in.pdb", + ) + else: + self.Logfile.error("%s: cannot find XYZIN for refinement" % self.xtalID) + self.error = True + return xyzin, xyzout + + def get_libin_libout(self, Serial): + ####################################################### + # LIBIN & LIBOUT + libin = None + libout = None + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, self.compoundID + ".cif") + ): + libin = os.path.join( + self.ProjectPath, self.xtalID, self.compoundID + ".cif" + ) + libout = os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + Serial, + "refine_" + Serial + ".cif", + ) + else: + self.Logfile.error("%s: cannot find CIF file for refinement" % self.xtalID) + self.error = True + return libin, libout + + def write_refinement_in_progress(self): + ####################################################### + # we write 'REFINEMENT_IN_PROGRESS' immediately to avoid unncessary refiment + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + os.system("touch REFINEMENT_IN_PROGRESS") + + def clean_up_before_refinement(self): + ####################################################### + # clean up! + # and remove all files which will be re-created by current refinement cycle + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + os.system( + "/bin/rm refine.pdb refine.mtz refine.split.bound-state.pdb" + " validation_summary.txt validate_ligands.txt 2fofc.map fofc.map" + " refine_molprobity.log" + ) + + def load_modules(self, cmd): + ####################################################### + # PHENIX stuff (if working at DLS) + if os.getcwd().startswith("/dls"): + cmd += "module load phenix/1.20\n" + cmd += "module load buster/20240123\n" + cmd += "module load graphviz\n" + return cmd + + def get_source_line(self, cmd): + if "bash" in os.getenv("SHELL"): + cmd += 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"\n' + return cmd + + def set_refinement_status(self, cmd): + cmd += ( + "$CCP4/bin/ccp4-python " + " $XChemExplorer_DIR/xce/helpers/update_status_flag.py " + + self.datasource + + " " + + self.xtalID + + " RefinementStatus running\n" + ) + return cmd + + def add_buster_command( + self, + cmd, + xyzin, + hklin, + libin, + Serial, + anisotropic_Bfactor, + update_water, + refine_ligand_occupancy, + ignore_sanity_check, + ): + cmd += ( + "refine " + " -p %s" % xyzin + + " -m %s" % hklin + + " -l %s" % libin + + " -autoncs" + + anisotropic_Bfactor + + update_water + + refine_ligand_occupancy + + ignore_sanity_check + + " -d Refine_%s\n" % str(Serial) + ) + return cmd + + def run_giant_score_model(self, cmd, cycle): + if os.path.isfile( + os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-pandda-model.pdb" + ) + ): + cmd += ( + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + cycle + + "\n" + + "module load ccp4/7.1.018\n" + + "giant.score_model " + " pdb1=../%s-pandda-model.pdb " % self.xtalID + " mtz1=../dimple.mtz " + " pdb2=refine.pdb " + " mtz2=refine.mtz\n" + ) + return cmd + + def add_validation(self, cmd, cycle, program): + buster_report = "" + if program == "refmac": + Serial = "_" + cycle + elif program == "buster": + Serial = "" + if os.getcwd().startswith("/dls"): + buster_report += ( + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + cycle + + "\n" + ) + buster_report += ( + "corr -p refine.pdb -m refine.mtz -F 2FOFCWT -P PH2FOFCWT\n" + ) + buster_report += "cd " + self.ProjectPath + "/" + self.xtalID + "\n" + buster_report += ( + "export BDG_TOOL_MOGUL=" + "/dls_sw/apps/CSDS/2024.1.0/ccdc-software/mogul/bin/mogul\n" + ) + buster_report += "buster-report -d Refine_%s\n" % cycle + + cmd += ( + "\n" + buster_report + "cd " + self.ProjectPath + "/" + self.xtalID + "\n" + "ln -s ./Refine_%s/refine%s.pdb refine.pdb\n" % (cycle, Serial) + + "ln -s ./Refine_%s/refine%s.mtz refine.mtz\n" % (cycle, Serial) + + "ln -s refine.pdb refine.split.bound-state.pdb\n" + "\n" + "phenix.molprobity refine%s.pdb refine%s.mtz\n" % (Serial, Serial) + + "/bin/mv molprobity.out refine_molprobity.log\n" + "mmtbx.validate_ligands refine%s.pdb refine%s.mtz LIG" + " > validate_ligands.txt\n" % (Serial, Serial) + "\n" + "mmtbx.validation_summary refine.pdb > validation_summary.txt\n" + "\n" + ) + return cmd + + def calculate_maps(self, cmd, program): + if program == "refmac": + FWT = "FWT" + PHWT = "PHWT" + DELFWT = "DELFWT" + PHDELWT = "PHDELWT" + elif program == "buster": + FWT = "2FOFCWT" + PHWT = "PH2FOFCWT" + DELFWT = "FOFCWT" + PHDELWT = "PHFOFCWT" + cmd += ( + "cd " + self.ProjectPath + "/" + self.xtalID + "\n" + "\n" + "fft hklin refine.mtz mapout 2fofc.map << EOF\n" + " labin F1=%s PHI=%s\n" % (FWT, PHWT) + " grid samp 4.5\n" + "EOF\n" + "\n" + "fft hklin refine.mtz mapout fofc.map << EOF\n" + " labin F1=%s PHI=%s\n" % (DELFWT, PHDELWT) + " grid samp 4.5\n" + "EOF\n" + "\n" + ) + return cmd + + def run_edstats(self, cmd, resh, resl): + cmd += ( + "\n" + "edstats XYZIN refine.pdb MAPIN1 2fofc.map MAPIN2 fofc.map OUT" + " refine.edstats << eof\n" + " resl={0!s}\n".format(resl) + " resh={0!s}\n".format(resh) + "eof\n" + "\n" + ) + return cmd + + def update_database(self, cmd, Serial): + date = datetime.strftime(datetime.now(), "%Y-%m-%d_%H-%M-%S.%f")[:-4] + user = getpass.getuser() + ccp4_module = "" # need to source again, because giant.score_model still needs + # outdated version which does not have gemmi + if self.ProjectPath.startswith("/dls"): + ccp4_module = "module load ccp4/7.1.018" + cmd += "\n" + ccp4_module + "\n" "$CCP4/bin/ccp4-python " + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "update_data_source_after_refinement.py", + ) + " %s %s %s %s %s %s\n" % ( + self.datasource, + self.xtalID, + self.ProjectPath, + os.path.join(self.ProjectPath, self.xtalID, "Refine_" + Serial), + user, + date, + ) + cmd += "/bin/rm %s/%s/REFINEMENT_IN_PROGRESS\n" % ( + self.ProjectPath, + self.xtalID, + ) + + return cmd + + def write_refinement_script(self, cmd, program): + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + f = open(program + ".sh", "w") + f.write(cmd) + f.close() + + def run_script(self, program, external_software, Serial, xce_logfile, slurm_token): + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + slurm.submit_cluster_job( + "xce_{!s}".format(program), + "{!s}.sh".format(program), + xce_logfile, + slurm_token, + tasks=8, + ) + + def RunBuster( + self, + Serial, + RefmacParams, + external_software, + xce_logfile, + covLinkAtomSpec, + slurm_token, + ): + if RefmacParams is None: + anisotropic_Bfactor = " -M ADP " + update_water = "" + else: + if "ANIS" in RefmacParams["BREF"]: + anisotropic_Bfactor = " -M ADP " + else: + anisotropic_Bfactor = " -M TLSbasic " + + if "WATER" in RefmacParams["WATER"]: + update_water = " -WAT " + else: + update_water = "" + + if "off" in RefmacParams["SANITY"]: + ignore_sanity_check = " StopOnGellySanityCheckError=no " + else: + ignore_sanity_check = "" + + self.error = False + + if os.path.isfile(xce_logfile): + self.Logfile = XChemLog.updateLog(xce_logfile) + Serial = str(Serial) + + if covLinkAtomSpec is not None: + self.make_covalent_link(covLinkAtomSpec, self.Logfile) + + # first check if refinement is ongoing and exit if yes + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, "REFINEMENT_IN_PROGRESS") + ): + self.Logfile.insert( + "cannot start new refinement for %s: *** REFINEMENT IN PROGRESS ***" + % self.xtalID + ) + return None + + hklin, hklout = self.get_hklin_hklout(Serial) + + resh, resl = XChemUtils.mtztools_gemmi(hklin).get_high_low_resolution_limits() + + xyzin, xyzout = self.get_xyzin_xyzout(Serial) + + refine_ligand_occupancy = "" + if RefmacParams is not None: + if "LIGOCC" in RefmacParams["LIGOCC"]: + ligand_info = XChemUtils.pdbtools(xyzin).get_residues_with_resname( + "LIG" + ) + if self.prepare_gelly_dat(ligand_info): + refine_ligand_occupancy = " -B user -Gelly gelly.dat " + + libin, libout = self.get_libin_libout(Serial) + + self.clean_up_before_refinement() + + self.write_refinement_in_progress() + + cmd = "#!/bin/bash\n. /etc/profile.d/modules.sh\n" + + cmd = self.load_modules(cmd) + + cmd = self.get_source_line(cmd) + + cmd = self.set_refinement_status(cmd) + + cmd = self.add_buster_command( + cmd, + xyzin, + hklin, + libin, + Serial, + anisotropic_Bfactor, + update_water, + refine_ligand_occupancy, + ignore_sanity_check, + ) + + cmd = self.add_validation(cmd, Serial, "buster") + + cmd = self.run_giant_score_model(cmd, Serial) + + cmd = self.calculate_maps(cmd, "buster") + + cmd = self.run_edstats(cmd, resh, resl) + + cmd = self.update_database(cmd, Serial) + + if self.error: + self.Logfile.error( + "%s: cannot start refinement; check error message above" % self.xtalID + ) + else: + self.Logfile.insert( + "%s: writing buster.sh file in %s" + % (self.xtalID, os.path.join(self.ProjectPath, self.xtalID)) + ) + self.write_refinement_script(cmd, "buster") + self.Logfile.insert("%s: starting refinement..." % self.xtalID) + self.run_script( + "buster", external_software, Serial, xce_logfile, slurm_token + ) + + def prepare_gelly_dat(self, ligand_info): + found_ligand = False + gelly = "NOTE BUSTER_SET Ligand = " + for n, lig in enumerate(ligand_info): + resseq = lig[1] + chain = lig[2] + if n == 0: + gelly += "{ %s|%s }" % (chain.replace(" ", ""), resseq.replace(" ", "")) + else: + gelly += " + { %s|%s }" % ( + chain.replace(" ", ""), + resseq.replace(" ", ""), + ) + found_ligand = True + if "{" in gelly: + gelly += "\n" + gelly += ( + "NOTE BUSTER_SET NotLigand = \\ Ligand\n" + "NOTE BUSTER_CONSTANT OCC NotLigand \n" + "NOTE BUSTER_COMBINE OCC Ligand \n" + "NOTE BUSTER_COMBINE B Ligand \n" + ) + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + f = open("gelly.dat", "w") + f.write(gelly) + f.close() + return found_ligand + + def RunRefmac( + self, + Serial, + RefmacParams, + external_software, + xce_logfile, + covLinkAtomSpec, + slurm_token, + ): + if os.path.isfile(xce_logfile): + Logfile = XChemLog.updateLog(xce_logfile) + Serial = str(Serial) + + if covLinkAtomSpec is not None: + self.make_covalent_link(covLinkAtomSpec, Logfile) + + # first check if refinement is ongoing and exit if yes + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, "REFINEMENT_IN_PROGRESS") + ): + # coot.info_dialog('*** REFINEMENT IN PROGRESS ***') + Logfile.insert( + "cannot start new refinement for %s: *** REFINEMENT IN PROGRESS ***" + % self.xtalID + ) + return None + + ####################################################### + # HKLIN & HKLOUT + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, self.xtalID + ".free.mtz") + ): + RefmacParams["HKLIN"] = "HKLIN " + os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + ".free.mtz" + ) + else: + Logfile.error( + "%s: cannot find HKLIN for refinement; aborting..." % self.xtalID + ) + return None + RefmacParams["HKLOUT"] = "HKLOUT " + os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + Serial, + "refine_" + Serial + ".mtz", + ) + + ####################################################### + # XYZIN & XYZOUT + RefmacParams["XYZIN"] = "XYZIN " + os.path.join( + self.ProjectPath, self.xtalID, "Refine_" + Serial, "in.pdb" + ) + RefmacParams["XYZOUT"] = "XYZOUT " + os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + Serial, + "refine_" + Serial + ".pdb", + ) + + ####################################################### + # LIBIN & LIBOUT + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, self.compoundID + ".cif") + ): + RefmacParams["LIBIN"] = ( + "LIBIN " + + self.ProjectPath + + "/" + + self.xtalID + + "/" + + self.compoundID + + ".cif \\\n" + ) + RefmacParams["LIBOUT"] = ( + "LIBOUT " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + Serial + + "/refine_" + + Serial + + ".cif \\\n" + ) + + ####################################################### + # TLSIN & TLSOUT + findTLS = "\n" + if RefmacParams["TLS"].startswith("refi"): + if external_software["phenix.find_tls_groups"]: + findTLS = ( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "phenix_find_TLS_groups.py", + ) + + " in.pdb\n" + ) + RefmacParams["TLSIN"] = ( + "TLSIN " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + Serial + + "/refmac.tls \\\n" + ) + RefmacParams["TLSOUT"] = ( + "TLSOUT " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + Serial + + "/refine.tls \\\n" + ) + else: + RefmacParams["TLS"] = "\n" + + print("==> XCE: assembling refmac.csh") + + ####################################################### + # we write 'REFINEMENT_IN_PROGRESS' immediately to avoid unncessary refiment + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + os.system("touch REFINEMENT_IN_PROGRESS") + + ####################################################### + # Database updates: + # no DB will be specified when a reference model is built and refined + refinementStatus = "" + updateDB = "" + date = datetime.strftime(datetime.now(), "%Y-%m-%d_%H-%M-%S.%f")[:-4] + user = getpass.getuser() + if os.path.isfile(self.datasource): + refinementStatus = ( + "$CCP4/bin/ccp4-python" + " $XChemExplorer_DIR/xce/helpers/update_status_flag.py %s %s %s %s\n" + % (self.datasource, self.xtalID, "RefinementStatus", "running") + ) + updateDB = ( + "$CCP4/bin/ccp4-python " + + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "update_data_source_after_refinement.py", + ) + + " %s %s %s %s %s %s\n" + % ( + self.datasource, + self.xtalID, + self.ProjectPath, + os.path.join(self.ProjectPath, self.xtalID, "Refine_" + Serial), + user, + date, + ) + ) + + ####################################################### + # clean up! + # and remove all files which will be re-created by current refinement cycle + os.system( + "/bin/rm refine.pdb refine.mtz refine.split.bound-state.pdb" + " validation_summary.txt validate_ligands.txt 2fofc.map fofc.map" + " refine_molprobity.log" + ) + + ####################################################### + # weight + if str(RefmacParams["MATRIX_WEIGHT"]).lower() == "auto": + weight = "weight AUTO\n" + else: + weight = "weight matrix " + str(RefmacParams["MATRIX_WEIGHT"]) + "\n" + + ####################################################### + # PHENIX stuff + + spider_plot = "" + if os.path.isfile( + os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-ensemble-model.pdb" + ) + ): + if os.path.isfile( + os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-pandda-input.mtz" + ) + ): + pdb_two = os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-ensemble-model.pdb" + ) + mtz_two = os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-pandda-input.mtz" + ) + pdb_one = os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + str(Serial), + "refine_" + str(Serial) + ".pdb", + ) + mtz_one = os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + str(Serial), + "refine_" + str(Serial) + ".mtz", + ) + spider_plot = ( + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + Serial + + "\n" + "\n" + "giant.score_model pdb1=%s mtz1=%s pdb2=%s mtz2=%s" + " res_names=LIG,UNL,DRG,FRG\n" + % (pdb_one, mtz_one, pdb_two, mtz_two) + ) + + refmacCmds = ( + "#!/bin/bash\n" + + ". /etc/profile.d/modules.sh\n" + + 'export XChemExplorer_DIR="' + + os.getenv("XChemExplorer_DIR") + + '"\n' + + "module load phenix/1.20\n" + + "module load buster/20240123\n" + + "module load ccp4\n" + + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + Serial + + "\n" + + refinementStatus + + "\n" + + findTLS + + "refmac5 " + + RefmacParams["HKLIN"] + + " " + + RefmacParams["HKLOUT"] + + " " + + RefmacParams["XYZIN"] + + " " + + RefmacParams["XYZOUT"] + + " " + + RefmacParams["LIBIN"] + + " " + + RefmacParams["LIBOUT"] + + " " + + RefmacParams["TLSIN"] + + " " + + RefmacParams["TLSOUT"] + + " " + + "<< EOF > refmac.log\n" + + "make -hydrogen ALL" + + "-hout NO " + + "-peptide NO " + + "-cispeptide YES " + + "-ssbridge YES " + + "-symmetry YES " + + "-sugar YES " + + "-connectivity NO " + + "-link NO\n" + + RefmacParams["NCS"] + + "refi -type REST -resi MLKF -meth CGMAT\n" + + RefmacParams["BREF"] + + RefmacParams["TLS"] + + RefmacParams["TWIN"] + + "ncyc " + + RefmacParams["NCYCLES"] + + "scal -type SIMP -LSSC -ANISO -EXPE\n" + + weight + + "solvent YES\n" + + "monitor MEDIUM -torsion 10.0 -distance 10.0 -angle 10.0 -plane 10.0 " + + "-chiral 10.0 -bfactor 10.0 -bsphere 10.0 -rbond 10.0 -ncsr 10.0\n" + + "labin FP=F SIGFP=SIGF FREE=FreeR_flag\n" + + "labout FC=FC FWT=FWT PHIC=PHIC PHWT=PHWT DELFWT=DELFWT PHDELWT=PHDELWT " + + "FOM=FOM\n" + + RefmacParams["TLSADD"] + + "\n" + + "DNAME " + + self.xtalID + + "\n" + + "END\n" + + "EOF\n" + + "\n" + + "phenix.molprobity refine_%s.pdb refine_%s.mtz\n" % (Serial, Serial) + + "/bin/mv molprobity.out refine_molprobity.log\n" + "mmtbx.validate_ligands refine_%s.pdb refine_%s.mtz LIG" + " > validate_ligands.txt\n" % (Serial, Serial) + + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "\n" + + "ln -s ./Refine_%s/refine_%s.pdb refine.pdb\n" % (Serial, Serial) + + "ln -s ./Refine_%s/refine_%s.mtz refine.mtz\n" % (Serial, Serial) + + "ln -s refine.pdb refine.split.bound-state.pdb\n" + + "\n" + + "ln -s Refine_%s/validate_ligands.txt .\n" % Serial + + "ln -s Refine_%s/refine_molprobity.log .\n" % Serial + + "mmtbx.validation_summary refine.pdb > validation_summary.txt\n" + + "\n" + + "fft hklin refine.mtz mapout 2fofc.map << EOF\n" + + "labin F1=FWT PHI=PHWT\n" + + "EOF\n" + + "\n" + + "fft hklin refine.mtz mapout fofc.map << EOF\n" + + "labin F1=DELFWT PHI=PHDELWT\n" + + "EOF\n" + + "\n" + + updateDB + + "\n" + + "/bin/rm %s/%s/REFINEMENT_IN_PROGRESS\n" % (self.ProjectPath, self.xtalID) + + "\n" + + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + Serial + + "\n" + + spider_plot + + "\n" + ) + + if os.path.isfile(xce_logfile): + Logfile.insert( + "writing refinement shell script to" + + os.path.join( + self.ProjectPath, self.xtalID, "Refine_" + Serial, "refmac.csh" + ) + ) + cmd = open( + os.path.join( + self.ProjectPath, self.xtalID, "Refine_" + Serial, "refmac.csh" + ), + "w", + ) + cmd.write(refmacCmds) + cmd.close() + + os.chdir(os.path.join(self.ProjectPath, self.xtalID, "Refine_" + Serial)) + Logfile.insert( + "changing directory to %s" + % (os.path.join(self.ProjectPath, self.xtalID, "Refine_" + Serial)) + ) + + slurm.submit_cluster_job( + "xce_refmac", "refmac.csh", xce_logfile, slurm_token, tasks=8 + ) + + def RefinementParams(self, RefmacParams): + self.RefmacParams = RefmacParams + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_title("Refmac Parameters") + self.vbox = gtk.VBox() + + self.hbox1 = gtk.HBox() + self.hbox1.add(gtk.Label("Refine")) + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseBfacRefinement) + for item in ["isotropic", "anisotropic"]: + self.cb.append_text(item) + if "ISOT" in self.RefmacParams["BREF"]: + self.cb.set_active(0) + if "ANIS" in self.RefmacParams["BREF"]: + self.cb.set_active(1) + self.hbox1.add(self.cb) + self.hbox1.add(gtk.Label("temperature factors")) + self.vbox.add(self.hbox1) + + self.hbox2 = gtk.HBox() + self.hbox2.add(gtk.Label("Number of Cycles: ")) + self.Ncycles = gtk.Entry() + self.Ncycles.add_events(gtk.gdk.KEY_RELEASE_MASK) + self.Ncycles.connect("key-release-event", self.on_key_release_Ncycles) + self.Ncycles.set_text(self.RefmacParams["NCYCLES"]) + self.hbox2.add(self.Ncycles) + self.vbox.add(self.hbox2) + + self.hbox3 = gtk.HBox() + self.hbox3.add(gtk.Label("MATRIX WEIGHT: ")) + self.MATRIX_WEIGHT = gtk.Entry() + self.MATRIX_WEIGHT.add_events(gtk.gdk.KEY_RELEASE_MASK) + self.MATRIX_WEIGHT.connect( + "key-release-event", self.on_key_release_MATRIX_WEIGHT + ) + self.MATRIX_WEIGHT.set_text(self.RefmacParams["MATRIX_WEIGHT"]) + self.hbox3.add(self.MATRIX_WEIGHT) + self.vbox.add(self.hbox3) + + self.TLS = gtk.CheckButton("TLS (find TLS groups with phenix.find_tls_groups)") + self.TLS.connect("toggled", self.TLSCallback) + if self.RefmacParams["TLS"] == "refi tlsc 10\n": + self.TLS.set_active(True) + self.vbox.pack_start(self.TLS, False) + + self.NCS = gtk.CheckButton("NCS (if applicable") + self.NCS.connect("toggled", self.NCSCallback) + if self.RefmacParams["NCS"] == "NCSR LOCAL\n": + self.NCS.set_active(True) + self.vbox.pack_start(self.NCS, False) + + self.TWIN = gtk.CheckButton("Twin?") + self.TWIN.connect("toggled", self.TWINCallback) + if self.RefmacParams["TWIN"] == "TWIN\n": + self.TWIN.set_active(True) + self.vbox.pack_start(self.TWIN, False) + + self.OKbutton = gtk.Button(label="OK") + self.OKbutton.connect("clicked", self.OK) + self.vbox.add(self.OKbutton) + + self.window.add(self.vbox) + self.window.show_all() + return self.RefmacParams + + def TLSCallback(self, widget): + if widget.get_active(): + self.RefmacParams["TLS"] = "refi tlsc 10\n" + self.RefmacParams["TLSIN"] = "refmac.tls\n" + self.RefmacParams["TLSOUT"] = "out.tls\n" + self.RefmacParams["TLSADD"] = "TLSO ADDU\n" + else: + self.RefmacParams["TLS"] = "" + self.RefmacParams["TLSIN"] = "" + self.RefmacParams["TLSOUT"] = "" + self.RefmacParams["TLSADD"] = "" + return self.RefmacParams + + def NCSCallback(self, widget): + if widget.get_active(): + self.RefmacParams["NCS"] = "NCSR LOCAL\n" + else: + self.RefmacParams["NCS"] = "" + return self.RefmacParams + + def ChooseBfacRefinement(self, widget): + if widget.get_active_text() == "isotropic": + self.RefmacParams["BREF"] = " bref ISOT\n" + if widget.get_active_text() == "anisotropic": + self.RefmacParams["BREF"] = " bref ANIS\n" + return self.RefmacParams + + def on_key_release_Ncycles(self, widget, event): + print(widget.get_text()) + self.RefmacParams["NCYCLES"] = widget.get_text() + return self.RefmacParams + + def on_key_release_MATRIX_WEIGHT(self, widget, event): + self.RefmacParams["MATRIX_WEIGHT"] = widget.get_text() + return self.RefmacParams + + def TWINCallback(self, widget): + if widget.get_active(): + self.RefmacParams["TWIN"] = "TWIN\n" + else: + self.RefmacParams["TWIN"] = "" + return self.RefmacParams + + def OK(self, widget): + self.window.destroy() + + def ParamsFromPreviousCycle(self, Serial): + RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + "WATER": "", + "LIGOCC": "", + "SANITY": "", + } + + if os.path.isfile( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(Serial) + + "/refmac.csh" + ): + for line in open( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(Serial) + + "/refmac.csh" + ): + if line.startswith("refi tlsc"): + RefmacParams["TLS"] = line + if line.startswith("TLSO"): + RefmacParams["TLSADD"] = line + if line.startswith("NCSR LOCAL"): + RefmacParams["NCS"] = line + if line.startswith(" bref "): + RefmacParams["BREF"] = line + if line.startswith("ncyc"): + RefmacParams["Ncycles"] = line.split()[1] + if line.startswith("weight"): + RefmacParams["MATRIX_WEIGHT"] = line.split()[len(line.split()) - 1] + if line.startswith("TWIN"): + RefmacParams["TWIN"] = line + elif os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "multi-state-restraints.refmac.params", + ) + ): + for line in open( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "multi-state-restraints.refmac.params", + ) + ): + if "refi tlsc" in line: + RefmacParams["TLS"] = line + if "TLSO" in line: + RefmacParams["TLSADD"] = line + if "NCSR LOCAL" in line: + RefmacParams["NCS"] = line + if "bref" in line: + RefmacParams["BREF"] = line + if "ncyc" in line: + RefmacParams["Ncycles"] = line.split()[1] + if "weight" in line: + RefmacParams["MATRIX_WEIGHT"] = line.split()[len(line.split()) - 1] + if "TWIN" in line: + RefmacParams["TWIN"] = line + + return RefmacParams + + def GetRefinementHistory(self): + RefinementCycle = [] + RcrystList = [] + RfreeList = [] + + found = False + for item in glob.glob(os.path.join(self.ProjectPath, self.xtalID, "*")): + if item.startswith(os.path.join(self.ProjectPath, self.xtalID, "Refine_")): + print(item[item.rfind("_") + 1 :]) + RefinementCycle.append(int(item[item.rfind("_") + 1 :])) + found = True + if found: + for cycle in sorted(RefinementCycle): + try: + found_Rcryst = False + found_Rfree = False + newestPDB = max( + glob.iglob( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(cycle) + + "/refine_" + + str(cycle) + + ".pdb" + ), + key=os.path.getctime, + ) + for line in open(newestPDB): + if line.startswith( + "REMARK 3 R VALUE (WORKING + TEST SET) :" + ): + Rcryst = line.split()[9] + RcrystList.append(float(Rcryst)) + found_Rcryst = True + if line.startswith( + "REMARK 3 FREE R VALUE :" + ): + Rfree = line.split()[6] + RfreeList.append(float(Rfree)) + found_Rfree = True + if not found_Rcryst: + RcrystList.append(0) + if not found_Rfree: + RfreeList.append(0) + except ValueError: + RcrystList.append(0) + RfreeList.append(0) + else: + RefinementCycle = [0] + RcrystList = [0] + RfreeList = [0] + print(RefinementCycle, RcrystList, RfreeList) + return (sorted(RefinementCycle), RcrystList, RfreeList) + + +class panddaRefine(object): + def __init__(self, ProjectPath, xtalID, compoundID, datasource): + self.ProjectPath = ProjectPath + self.xtalID = xtalID + self.compoundID = compoundID + self.datasource = datasource + + def make_covalent_link(self, covLinkAtomSpec, Logfile): + residuesToModify = ["CYS", "SER"] + + atom1 = covLinkAtomSpec[1][5] + atom2 = covLinkAtomSpec[2][5] + residue_1 = covLinkAtomSpec[3] + residue_2 = covLinkAtomSpec[4] + + if residue_2 in residuesToModify: + bond_text = ( + "LINK: RES-NAME-1 %s FILE-1 %s_acedrg.cif ATOM-NAME-1 %s RES-NAME-2" + " %s ATOM-NAME-2 %s" + % (residue_1, self.compoundID, atom1, residue_2, atom2) + ) + else: + bond_text = ( + "LINK: RES-NAME-1 %s FILE-1 %s_acedrg.cif ATOM-NAME-1 %s RES-NAME-2" + " %s ATOM-NAME-2 %s" + % (residue_2, self.compoundID, atom2, residue_1, atom1) + ) + + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + f = open("covalent_bond.txt", "w") + f.write(bond_text) + f.close() + + # seems somewhat unncessary, but acedrg does not like some certain descriptions + # generated by phenix.elbow + os.system("acedrg -c %s.cif -o %s_acedrg" % (self.compoundID, self.compoundID)) + + os.system("acedrg -L covalent_bond.txt -o %s" % self.compoundID) + + if os.path.isfile("%s_link.cif" % self.compoundID): + Logfile.insert("succefully created link file %s_link.cif" % self.compoundID) + os.system("/bin/rm %s.cif" % self.compoundID) + os.system("ln -s %s_link.cif %s.cif" % (self.compoundID, self.compoundID)) + else: + Logfile.error( + "could not create linkfile; please check logs in %s/%s" + % (self.ProjectPath, self.xtalID) + ) + + def RunQuickRefine( + self, + Serial, + RefmacParams, + external_software, + xce_logfile, + refinementProtocol, + covLinkAtomSpec, + slurm_token, + ): + Logfile = XChemLog.updateLog(xce_logfile) + Logfile.insert("preparing files for giant.quick_refine") + # panddaSerial because giant.quick_refine writes Refine_0001 instead of Refine_1 + panddaSerial = (4 - len(str(Serial))) * "0" + str(Serial) + + make_all_links = True + add_links_line = "" + + if covLinkAtomSpec is not None: + self.make_covalent_link(covLinkAtomSpec, Logfile) + + # first check if refinement is ongoing and exit if yes + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, "REFINEMENT_IN_PROGRESS") + ): + Logfile.insert( + "cannot start new refinement for %s: *** REFINEMENT IN PROGRESS ***" + % self.xtalID + ) + return None + + ####################################################### + # HKLIN & HKLOUT + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, self.xtalID + ".free.mtz") + ): + RefmacParams["HKLIN"] = os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + ".free.mtz" + ) + elif os.path.isfile( + os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-pandda-input.mtz" + ) + ): + RefmacParams["HKLIN"] = os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-pandda-input.mtz" + ) + else: + Logfile.error( + "%s: cannot find HKLIN for refinement; aborting..." % self.xtalID + ) + return None + + ####################################################### + # LIBIN & LIBOUT + found_cif = False + if os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, self.compoundID + ".cif") + ): + found_cif = True + RefmacParams["LIBIN"] = os.path.join( + self.ProjectPath, self.xtalID, self.compoundID + ".cif" + ) + if not found_cif: + # this should actually not be necessary, but the following scenario can + # happen if a new data source is created from a file system, but smiles and + # compoundID where not updated; so the ligand may still be in the structure, + # but since the compoundID is unknown to the datasource its restraints + # won't be read in and refmac will fail + for file in glob.glob(os.path.join(self.ProjectPath, self.xtalID, "*")): + if file.endswith(".cif"): + RefmacParams["LIBIN"] = file + break + + ####################################################### + # giant_merge_conformations + Logfile.insert("trying to merge modified bound state with ground state") + if os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + self.xtalID + "-ensemble-model.pdb", + ) + ): + Logfile.insert( + "seems to be an initial refinement after pandda.export," + " no need to merge the conformations" + ) + os.chdir( + os.path.join( + self.ProjectPath, self.xtalID, "cootOut", "Refine_" + str(Serial) + ) + ) + Logfile.insert( + "running giant.make_restraints %s:" % self.xtalID + + "-ensemble-model.pdb" + ) + cmd = ( + 'export XChemExplorer_DIR="%s"\n' % os.getenv("XChemExplorer_DIR") + + "module load buster/20240123\n" + + "module load ccp4/7.1.018\n" + + "giant.make_restraints %s-ensemble-model.pdb" % self.xtalID + ) + Logfile.insert(cmd + "\n") + os.system(cmd) + elif os.path.isfile( + os.path.join(self.ProjectPath, self.xtalID, "refine.split.ground-state.pdb") + ): + Logfile.insert( + "found model of ground state: " + + os.path.join( + self.ProjectPath, self.xtalID, "refine.split.ground-state.pdb" + ) + ) + if os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "refine.modified.pdb", + ) + ): + Logfile.insert("found model of modified bound state") + os.chdir( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + ) + ) + ground_state = os.path.join( + self.ProjectPath, self.xtalID, "refine.split.ground-state.pdb" + ) + bound_state = "refine.modified.pdb" + Logfile.insert( + "running giant.merge_conformations major=%s minor=%s" + % (ground_state, bound_state) + ) + if os.getcwd().startswith("/dls"): + cmd = ( + 'export XChemExplorer_DIR="%s"\n' + % os.getenv("XChemExplorer_DIR") + + "module load ccp4/7.1.018\n" + "giant.merge_conformations major=%s minor=%s" + " reset_all_occupancies=False options.major_occupancy=1.0" + " options.minor_occupancy=1.0" % (ground_state, bound_state) + ) + else: + cmd = ( + "giant.merge_conformations major=%s minor=%s" + " reset_all_occupancies=False options.major_occupancy=1.0" + " options.minor_occupancy=1.0" % (ground_state, bound_state) + ) + Logfile.insert(cmd + "\n") + os.system(cmd) + link_line = "" + for line in open(bound_state): + if line.startswith("LINK"): + Logfile.insert("found LINK: " + line[:-1]) + link_line += line + if link_line != "": + if os.path.isfile("multi-state-model.pdb"): + for line in open("multi-state-model.pdb"): + if line.startswith("CRYST"): + Logfile.insert( + "adding LINK lines to multi-state-model.pdb" + ) + out = link_line + line + else: + out += line + Logfile.insert("writing updated multi-state-model.pdb") + f = open("multi-state-model.pdb", "w") + f.write(out) + f.close() + else: + Logfile.error("cannot find multi-state-model.pdb") + else: + Logfile.error( + "cannot find modified version of bound state in %s" + % os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + ) + ) + return None + else: + if os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "refine.modified.pdb", + ) + ): + os.chdir( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + ) + ) + Logfile.warning( + "%s: ground-state model does not exist," + " but refine.modified.pdb does exist" % self.xtalID + ) + Logfile.warning( + "This may be a case where there are no differences" + " between bound and ground state" + ) + Logfile.warning( + "creating symbolic link:" + " ln -s refine.modified.pdb %s-ensemble-model.pdb" % self.xtalID + ) + os.system( + "ln -s refine.modified.pdb %s-ensemble-model.pdb" % self.xtalID + ) + # note: after first cycle of refinement, REFMAC will remove alternate + # conformer from the ligand + # i.e. need to link refine.pdb to refine.split.bound-state.pdb + make_all_links = False + add_links_line = "ln -s refine.pdb refine.split.bound-state.pdb" + Logfile.insert("trying to continue with refinement") + else: + Logfile.error( + "cannot find any suitable PDB file for refinement, aborting..." + ) + return None + + ####################################################### + # checking if input PDB files are present + Logfile.insert("checking if input PDB files for REFMAC are present") + if os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + self.xtalID + "-ensemble-model.pdb", + ) + ): + RefmacParams["XYZIN"] = os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + self.xtalID + "-ensemble-model.pdb", + ) + elif os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "multi-state-model.pdb", + ) + ): + RefmacParams["XYZIN"] = os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "multi-state-model.pdb", + ) + else: + Logfile.error( + "cannot find multi-state-model.pdb in %s; aborting..." + % os.path.join( + self.ProjectPath, self.xtalID, "cootOut", "Refine_" + str(Serial) + ) + ) + return None + + ####################################################### + # checking if multi-state-restraints.refmac.params file is present + if os.path.isfile( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "multi-state-restraints.refmac.params", + ) + ): + # add REFMAC keywords to multi-state-restraints.refmac.params + with open("multi-state-restraints.refmac.params", "a") as refmacParams: + refmacParams.write(RefmacParams["BREF"] + "\n") + refmacParams.write(RefmacParams["TLS"] + "\n") + refmacParams.write(RefmacParams["TWIN"] + "\n") + refmacParams.write("ncyc " + RefmacParams["NCYCLES"] + "\n") + if str(RefmacParams["MATRIX_WEIGHT"]).lower() == "auto": + refmacParams.write("weight AUTO" + "\n") + else: + refmacParams.write( + "weight matrix " + str(RefmacParams["MATRIX_WEIGHT"]) + "\n" + ) + refmacParams.write(RefmacParams["TLSADD"] + "\n") + else: + Logfile.warning( + "cannot find multi-state-restraints.refmac.params in %s!" + % os.path.join( + self.ProjectPath, self.xtalID, "cootOut", "Refine_" + str(Serial) + ) + ) + try: + os.chdir( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + ) + ) + Logfile.insert( + "checking if %s-ensemble-model.pdb contains residue of type" + " LIG, DRG, FRG, UNK or UNL" % self.xtalID + ) + knowLigandIDs = ["LIG", "DRG", "FRG", "UNK", "UNL"] + ligandsInFile = XChemUtils.pdbtools( + self.xtalID + "-ensemble-model.pdb" + ).find_ligands() + found_lig = False + for lig in ligandsInFile: + if lig[0] in knowLigandIDs: + Logfile.insert("found ligand of type: " + lig[0]) + found_lig = True + if found_lig: + Logfile.warning( + "giant.make_restraints was not able to create" + " multi-state-restraints.refmac.params." + " Something may have gone wrong, but it could be that ligand" + " binding did not lead to displacement of water molecules or" + " rearrangement of protein side-chains." + " Hence, there is no difference between the bound-state and" + " the ground-state." + " We will create an empty multi-state-restraints.refmac.params" + " which may contain additional REFMAC keywords and otherwise" + " try to continue with refinement" + ) + os.system("touch multi-state-restraints.refmac.params") + else: + Logfile.error( + "%s-ensemble-model.pdb does not contain any modelled ligand;" + " aborting refinement" % self.xtalID + ) + return None + except OSError: + Logfile.error( + "directory does not exisit: %s" + % os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + ) + ) + Logfile.error("aborting refinement...") + return None + + ####################################################### + # we write 'REFINEMENT_IN_PROGRESS' immediately to avoid unncessary refinement + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + os.system("touch REFINEMENT_IN_PROGRESS") + + ####################################################### + # clean up! + # and remove all files which will be re-created by current refinement cycle + os.chdir(os.path.join(self.ProjectPath, self.xtalID)) + files_to_remove = ( + "refine.pdb " + "refine.mtz " + "refine.split.bound-state.pdb " + "refine.split.ground-state.pdb " + "validation_summary.txt " + "validate_ligands.txt " + "2fofc.map " + "fofc.map " + "refine_molprobity.log" + ) + os.system("/bin/rm %s" % files_to_remove) + + ####################################################### + # PANDDA validation @ spider plot + spider_plot = "" + if os.path.isfile( + os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-ensemble-model.pdb" + ) + ): + if os.path.isfile( + os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-pandda-input.mtz" + ) + ): + pdb_two = os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-ensemble-model.pdb" + ) + mtz_two = os.path.join( + self.ProjectPath, self.xtalID, self.xtalID + "-pandda-input.mtz" + ) + pdb_one = os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + str(panddaSerial), + "refine_" + str(Serial) + ".pdb", + ) + mtz_one = os.path.join( + self.ProjectPath, + self.xtalID, + "Refine_" + str(panddaSerial), + "refine_" + str(Serial) + ".mtz", + ) + spider_plot += ( + "giant.score_model pdb1=%s mtz1=%s pdb2=%s mtz2=%s" + " res_names=LIG,UNL,DRG,FRG\n" + % (pdb_one, mtz_one, pdb_two, mtz_two) + ) + + ####################################################### + # CCP4 & PHENIX stuff (if working at DLS) + module_load = "" + if os.getcwd().startswith("/dls"): + module_load = "module load ccp4/7.1.018\n" + module_load += "module load phenix/1.20\n" + + # 2017-07-20: for the time being this will explicitly source pandda since + # version 0.2 really only works at DLS + # 2020-11-02: will start using default ccp4 installation at DLS otherwise gemmi + # does not work + source = "" + if "bash" in os.getenv("SHELL"): + source = ( + 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"\n' + "\n" + ) + + if refinementProtocol == "pandda_refmac": + refinementProgram = "refmac" + refinementParams = os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "multi-state-restraints.refmac.params", + ) + mapCalculation = ( + "fft hklin refine.mtz mapout 2fofc.map << EOF\n" + "labin F1=FWT PHI=PHWT\n" + "EOF\n" + "\n" + "fft hklin refine.mtz mapout fofc.map << EOF\n" + "labin F1=DELFWT PHI=PHDELWT\n" + "EOF\n" + ) + elif refinementProtocol == "pandda_phenix": + if os.getcwd().startswith("/dls"): + module_load = "module load phenix/1.20\n" + + refinementProgram = "phenix" + refinementParams = os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "multi-state-restraints.phenix.params", + ) + mapCalculation = ( + "fft hklin refine.mtz mapout 2fofc.map << EOF\n" + "labin F1=2FOFCWT PHI=PH2FOFCWT\n" + "EOF\n" + "\n" + "fft hklin refine.mtz mapout fofc.map << EOF\n" + "labin F1=FOFCWT PHI=PHFOFCWT\n" + "EOF\n" + ) + + if make_all_links: + add_links_line = ( + "ln -s Refine_%s/refine_%s.split.bound-state.pdb" + " ./refine.split.bound-state.pdb\n" + % ( + panddaSerial, + Serial, + ) + + "ln -s Refine_%s/refine_%s.split.ground-state.pdb" + " ./refine.split.ground-state.pdb\n" + % ( + panddaSerial, + Serial, + ) + ) + + date = datetime.strftime(datetime.now(), "%Y-%m-%d_%H-%M-%S.%f")[:-4] + user = getpass.getuser() + + refmacCmds = ( + "#!/bin/bash\n" + + ". /etc/profile.d/modules.sh\n" + + module_load + + "\n" + + source + + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "\n" + "\n" + "$CCP4/bin/ccp4-python $XChemExplorer_DIR/xce/helpers/update_status_flag.py" + " %s %s %s %s\n" + % (self.datasource, self.xtalID, "RefinementStatus", "running") + + "\n" + "giant.quick_refine" + " input.pdb=%s" % RefmacParams["XYZIN"] + + " mtz=%s" % RefmacParams["HKLIN"] + + " cif=%s" % RefmacParams["LIBIN"] + + " program=%s" % refinementProgram + + " params=%s" % refinementParams + + " dir_prefix='Refine_'" + " out_prefix='refine_%s'" % str(Serial) + " split_conformations='False'" + "\n" + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(panddaSerial) + + "\n" + "ln -s " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(panddaSerial) + + "/refine_" + + str(Serial) + + "_001.pdb " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(panddaSerial) + + "/refine_" + + str(Serial) + + ".pdb" + + "\n" + "ln -s " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(panddaSerial) + + "/refine_" + + str(Serial) + + "_001.mtz " + + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(panddaSerial) + + "/refine_" + + str(Serial) + + ".mtz" + + "\n" + "giant.split_conformations" + " input.pdb='refine_%s.pdb'" % str(Serial) + " reset_occupancies=False" + " suffix_prefix=split" + "\n" + "giant.split_conformations" + " input.pdb='refine_%s.pdb'" % str(Serial) + " reset_occupancies=True" + " suffix_prefix=output " + "\n" + spider_plot + "\n" + "phenix.molprobity refine_%s.pdb refine_%s.mtz\n" % (Serial, Serial) + + "/bin/mv molprobity.out refine_molprobity.log\n" + "module load phenix/1.20\n" + "mmtbx.validate_ligands refine_%s.pdb refine_%s.mtz LIG" + " > validate_ligands.txt\n" % (Serial, Serial) + + "cd " + + self.ProjectPath + + "/" + + self.xtalID + + "\n" + "\n" + "ln -s Refine_%s/validate_ligands.txt .\n" % panddaSerial + + "ln -s Refine_%s/refine_molprobity.log .\n" % panddaSerial + + "\n" + + add_links_line + + "\n" + "mmtbx.validation_summary refine.pdb > validation_summary.txt\n" + "\n" + mapCalculation + "\n" + "$CCP4/bin/ccp4-python " + + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "update_data_source_after_refinement.py", + ) + + " %s %s %s %s %s %s\n" + % ( + self.datasource, + self.xtalID, + self.ProjectPath, + os.path.join( + self.ProjectPath, self.xtalID, "Refine_" + str(panddaSerial) + ), + user, + date, + ) + + "\n" + "/bin/rm %s/%s/REFINEMENT_IN_PROGRESS\n" % (self.ProjectPath, self.xtalID) + + "\n" + ) + + Logfile.insert( + "writing refinement shell script to" + + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "refmac.csh", + ) + ) + cmd = open( + os.path.join( + self.ProjectPath, + self.xtalID, + "cootOut", + "Refine_" + str(Serial), + "refmac.csh", + ), + "w", + ) + cmd.write(refmacCmds) + cmd.close() + + os.chdir( + os.path.join( + self.ProjectPath, self.xtalID, "cootOut", "Refine_" + str(Serial) + ) + ) + Logfile.insert( + "changing directory to %s" + % ( + os.path.join( + self.ProjectPath, self.xtalID, "cootOut", "Refine_" + str(Serial) + ) + ) + ) + + slurm.submit_cluster_job( + "refmac", "refmac.csh", xce_logfile, slurm_token, tasks=8 + ) + + def RefinementParams(self, RefmacParams): + self.RefmacParams = RefmacParams + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.window.connect("delete_event", gtk.main_quit) + self.window.set_border_width(10) + self.window.set_title("Refmac Parameters") + self.vbox = gtk.VBox() + + self.hbox1 = gtk.HBox() + self.hbox1.add(gtk.Label("Refine")) + self.cb = gtk.combo_box_new_text() + self.cb.connect("changed", self.ChooseBfacRefinement) + for item in ["isotropic", "anisotropic"]: + self.cb.append_text(item) + if "ISOT" in self.RefmacParams["BREF"]: + self.cb.set_active(0) + if "ANIS" in self.RefmacParams["BREF"]: + self.cb.set_active(1) + self.hbox1.add(self.cb) + self.hbox1.add(gtk.Label("temperature factors")) + self.vbox.add(self.hbox1) + + self.hbox2 = gtk.HBox() + self.hbox2.add(gtk.Label("Number of Cycles: ")) + self.Ncycles = gtk.Entry() + self.Ncycles.add_events(gtk.gdk.KEY_RELEASE_MASK) + self.Ncycles.connect("key-release-event", self.on_key_release_Ncycles) + self.Ncycles.set_text(self.RefmacParams["NCYCLES"]) + self.hbox2.add(self.Ncycles) + self.vbox.add(self.hbox2) + + self.hbox3 = gtk.HBox() + self.hbox3.add(gtk.Label("MATRIX WEIGHT: ")) + self.MATRIX_WEIGHT = gtk.Entry() + self.MATRIX_WEIGHT.add_events(gtk.gdk.KEY_RELEASE_MASK) + self.MATRIX_WEIGHT.connect( + "key-release-event", self.on_key_release_MATRIX_WEIGHT + ) + self.MATRIX_WEIGHT.set_text(self.RefmacParams["MATRIX_WEIGHT"]) + self.hbox3.add(self.MATRIX_WEIGHT) + self.vbox.add(self.hbox3) + + self.TLS = gtk.CheckButton("TLS (find TLS groups with phenix.find_tls_groups)") + self.TLS.connect("toggled", self.TLSCallback) + if self.RefmacParams["TLS"] == "refi tlsc 10\n": + self.TLS.set_active(True) + self.vbox.pack_start(self.TLS, False) + + self.NCS = gtk.CheckButton("NCS (if applicable") + self.NCS.connect("toggled", self.NCSCallback) + if self.RefmacParams["NCS"] == "NCSR LOCAL\n": + self.NCS.set_active(True) + self.vbox.pack_start(self.NCS, False) + + self.TWIN = gtk.CheckButton("Twin?") + self.TWIN.connect("toggled", self.TWINCallback) + if self.RefmacParams["TWIN"] == "TWIN\n": + self.TWIN.set_active(True) + self.vbox.pack_start(self.TWIN, False) + + self.OKbutton = gtk.Button(label="OK") + self.OKbutton.connect("clicked", self.OK) + self.vbox.add(self.OKbutton) + + self.window.add(self.vbox) + self.window.show_all() + return self.RefmacParams + + def TLSCallback(self, widget): + if widget.get_active(): + self.RefmacParams["TLS"] = "refi tlsc 10\n" + self.RefmacParams["TLSIN"] = "refmac.tls\n" + self.RefmacParams["TLSOUT"] = "out.tls\n" + self.RefmacParams["TLSADD"] = "TLSO ADDU\n" + else: + self.RefmacParams["TLS"] = "" + self.RefmacParams["TLSIN"] = "" + self.RefmacParams["TLSOUT"] = "" + self.RefmacParams["TLSADD"] = "" + return self.RefmacParams + + def NCSCallback(self, widget): + if widget.get_active(): + self.RefmacParams["NCS"] = "NCSR LOCAL\n" + else: + self.RefmacParams["NCS"] = "" + return self.RefmacParams + + def ChooseBfacRefinement(self, widget): + if widget.get_active_text() == "isotropic": + self.RefmacParams["BREF"] = " bref ISOT\n" + if widget.get_active_text() == "anisotropic": + self.RefmacParams["BREF"] = " bref ANIS\n" + return self.RefmacParams + + def on_key_release_Ncycles(self, widget, event): + print(widget.get_text()) + self.RefmacParams["NCYCLES"] = widget.get_text() + return self.RefmacParams + + def on_key_release_MATRIX_WEIGHT(self, widget, event): + self.RefmacParams["MATRIX_WEIGHT"] = widget.get_text() + return self.RefmacParams + + def TWINCallback(self, widget): + if widget.get_active(): + self.RefmacParams["TWIN"] = "TWIN\n" + else: + self.RefmacParams["TWIN"] = "" + return self.RefmacParams + + def OK(self, widget): + self.window.destroy() + + def ParamsFromPreviousCycle(self, Serial): + RefmacParams = { + "HKLIN": "", + "HKLOUT": "", + "XYZIN": "", + "XYZOUT": "", + "LIBIN": "", + "LIBOUT": "", + "TLSIN": "", + "TLSOUT": "", + "TLSADD": "", + "NCYCLES": "10", + "MATRIX_WEIGHT": "AUTO", + "BREF": " bref ISOT\n", + "TLS": "", + "NCS": "", + "TWIN": "", + } + + if os.path.isfile( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(Serial) + + "/refmac.csh" + ): + for line in open( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(Serial) + + "/refmac.csh" + ): + if line.startswith("refi tlsc"): + RefmacParams["TLS"] = line + if line.startswith("TLSO"): + RefmacParams["TLSADD"] = line + if line.startswith("NCSR LOCAL"): + RefmacParams["NCS"] = line + if line.startswith(" bref "): + RefmacParams["BREF"] = line + if line.startswith("ncyc"): + RefmacParams["Ncycles"] = line.split()[1] + if line.startswith("weight"): + RefmacParams["MATRIX_WEIGHT"] = line.split()[len(line.split()) - 1] + if line.startswith("TWIN"): + RefmacParams["TWIN"] = line + + return RefmacParams + + def GetRefinementHistory(self): + RefinementCycle = [] + RcrystList = [] + RfreeList = [] + + found = False + for item in glob.glob(os.path.join(self.ProjectPath, self.xtalID, "*")): + if item.startswith(os.path.join(self.ProjectPath, self.xtalID, "Refine_")): + print(item[item.rfind("_") + 1 :]) + RefinementCycle.append(int(item[item.rfind("_") + 1 :])) + found = True + if found: + for cycle in sorted(RefinementCycle): + try: + found_Rcryst = False + found_Rfree = False + newestPDB = max( + glob.iglob( + self.ProjectPath + + "/" + + self.xtalID + + "/Refine_" + + str(cycle) + + "/refine_" + + str(cycle) + + ".pdb" + ), + key=os.path.getctime, + ) + for line in open(newestPDB): + if line.startswith( + "REMARK 3 R VALUE (WORKING + TEST SET) :" + ): + Rcryst = line.split()[9] + RcrystList.append(float(Rcryst)) + found_Rcryst = True + if line.startswith( + "REMARK 3 FREE R VALUE :" + ): + Rfree = line.split()[6] + RfreeList.append(float(Rfree)) + found_Rfree = True + if not found_Rcryst: + RcrystList.append(0) + if not found_Rfree: + RfreeList.append(0) + except ValueError: + RcrystList.append(0) + RfreeList.append(0) + else: + RefinementCycle = [0] + RcrystList = [0] + RfreeList = [0] + print(RefinementCycle, RcrystList, RfreeList) + return (sorted(RefinementCycle), RcrystList, RfreeList) diff --git a/xce/lib/XChemThread.py b/xce/lib/XChemThread.py new file mode 100755 index 00000000..a204e40c --- /dev/null +++ b/xce/lib/XChemThread.py @@ -0,0 +1,3132 @@ +import csv +import glob +import math +import os +import pickle +from datetime import datetime + +from PyQt4 import QtCore + +from xce.lib import XChemDB +from xce.lib import XChemLog +from xce.lib import XChemMain +from xce.lib import XChemUtils +from xce.lib.cluster import slurm +from iotbx.reflection_file_reader import any_reflection_file + + +class synchronise_db_and_filesystem(QtCore.QThread): + """ + - remove broken links + - insert new samples in DB + - update data for existing samples + """ + + def __init__( + self, initial_model_directory, datasource, panddas_directory, xce_logfile, mode + ): + QtCore.QThread.__init__(self) + self.initial_model_directory = initial_model_directory + self.datasource = datasource + self.db = XChemDB.data_source(self.datasource) + self.all_samples_in_datasource = ( + self.db.get_all_samples_in_data_source_as_list() + ) + self.panddas_directory = panddas_directory + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.mode = mode + + def run(self): + self.Logfile.insert("synchronising database and filesystem") + self.Logfile.insert( + "current project directory: " + self.initial_model_directory + ) + + XChemMain.backup_soakDB(self.datasource, self.xce_logfile) + + # get list of xtals + + self.xtal_list = [] + progress_step = 1 + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + if self.mode != "project_directory": + # if only a single xtal is synched, then self.mode==xtalID + self.Logfile.insert("synchronising " + self.mode + " only") + self.xtal_list.append(self.mode) + else: + if len(glob.glob(os.path.join(self.initial_model_directory, "*"))) != 0: + progress_step = 100 / float( + len(glob.glob(os.path.join(self.initial_model_directory, "*"))) + ) + self.Logfile.insert( + "found " + + str(len(glob.glob(os.path.join(self.initial_model_directory, "*")))) + + " samples in project directory" + ) + for directory in sorted( + glob.glob(os.path.join(self.initial_model_directory, "*")) + ): + try: + os.chdir(directory) + except OSError: + # this could happen if the user accidentaly left a file in the + # project directory + continue + if os.listdir(directory) == []: + self.Logfile.warning(directory + " is empty; skipping...") + continue + xtal = directory[directory.rfind("/") + 1 :] + self.xtal_list.append(xtal) + + # go through list + + for xtal in self.xtal_list: + self.Logfile.insert("directory name: " + xtal + " = sampleID in database") + os.chdir(os.path.join(self.initial_model_directory, xtal)) + if xtal not in self.all_samples_in_datasource: + self.Logfile.insert("sampleID not found in database: inserting " + xtal) + self.db.execute_statement( + "insert into mainTable (CrystalName) values ('{0!s}');".format(xtal) + ) + self.all_samples_in_datasource.append(xtal) + + db_dict = self.db.get_db_dict_for_sample(xtal) + + db_dict["ProjectDirectory"] = self.initial_model_directory + + db_dict = self.sync_data_processing(xtal, db_dict) + + db_dict = self.sync_dimple_results(xtal, db_dict) + + db_dict = self.sync_compound_information(db_dict) + + db_dict = self.sync_refinement_results(xtal, db_dict) + + if db_dict != {}: + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "updating datasource for " + xtal, + ) + self.db.update_data_source(xtal, db_dict) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.Logfile.insert("database mainTable update finished") + self.Logfile.insert("updating panddaTable") + self.emit(QtCore.SIGNAL("update_status_bar(QString)"), "updating panddaTable") + self.sync_pandda_table_NEW() + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "database panddaTable update finished", + ) + self.Logfile.insert("database panddaTable update finished") + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + def sync_data_processing(self, xtal, db_dict): + # AIMLESS logfile + + # in case the MTZ file which is used for refinement is different to the one + # used for refinement + if os.path.isfile("refine.mtz"): + if os.path.isfile(xtal + ".free.mtz"): + freeMTZ = XChemUtils.mtztools(xtal + ".free.mtz") + nREFfree = freeMTZ.get_number_measured_reflections() + if os.path.isfile(xtal + ".mtz"): + procMTZ = XChemUtils.mtztools(xtal + ".mtz") + nREF = procMTZ.get_number_measured_reflections() + ( + CC, + errorMessage, + ) = freeMTZ.calculate_correlaton_between_intensities_in_mtzfiles( + xtal + ".mtz" + ) + self.Logfile.insert( + "%s: calculating CC between %s.free.mtz" + " (%s refl) and %s.mtz (%s refl): %s" + % (xtal, xtal, str(nREFfree), xtal, str(nREF), str(CC)) + ) + if errorMessage != "": + self.Logfile.insert( + "pointless failed with the following error: %s" + % errorMessage + ) + + try: + if float(CC) < 0.999: + self.Logfile.insert( + "correlation coefficient between the two files is below" + " 0.999; will try to understand from dimple.log which" + " one was used for initial map calculation" + ) + if os.path.isfile( + "dimple/dimple_rerun_on_selected_file/dimple/dimple.log" + ): + foundLine = False + mtzin = "" + for line in open( + "dimple/dimple_rerun_on_selected_file/dimple/" + "dimple.log" + ): + if foundLine: + mtzin = ( + line.replace(" ", "") + .replace("\n", "") + .replace("\r", "") + ) + self.Logfile.insert( + "%s was used for inital map calculation" + % mtzin + ) + break + if line.startswith(" --no-cleanup"): + foundLine = True + + if os.path.isfile(mtzin): + self.Logfile.insert( + "%s: mtzfile used for refinement is not the" + " same as the one chosen from autoprocessing" + % xtal + ) + self.Logfile.insert( + "%s: current mtzfile after autoprocessing: %s" + % (xtal, os.path.realpath(xtal + ".mtz")) + ) + self.Logfile.insert( + "%s: removing links for %s.mtz/%s.log" + % (xtal, xtal, xtal) + ) + os.system("/bin/rm %s.mtz 2> /dev/null" % xtal) + os.system("/bin/rm %s.log 2> /dev/null" % xtal) + self.Logfile.insert( + "linking %s to %s.mtz" + % (os.path.relpath(mtzin), xtal) + ) + os.symlink(os.path.relpath(mtzin), xtal + ".mtz") + for logfile in glob.glob( + os.path.join(mtzin[: mtzin.rfind("/")], "*log") + ): + self.Logfile.insert( + "linking %s to %s.log" + % (os.path.relpath(logfile), xtal) + ) + os.symlink( + os.path.relpath(logfile), xtal + ".log" + ) + break + + except ValueError: + self.Logfile.insert( + "something went wrong: calculated CC value" + " does not seem to be a floating point number" + ) + + found_logfile = False + if os.path.isfile(xtal + ".log"): + found_logfile = True + db_dict["DataProcessingPathToLogfile"] = os.path.realpath(xtal + ".log") + db_dict["DataProcessingLOGfileName"] = xtal + ".log" + if ( + db_dict["DataCollectionOutcome"] == "None" + or db_dict["DataCollectionOutcome"] == "" + ): + db_dict["DataCollectionOutcome"] = "success" + aimless_results = XChemUtils.parse().read_aimless_logfile( + db_dict["DataProcessingPathToLogfile"] + ) + db_dict.update(aimless_results) + else: + db_dict["DataProcessingPathToLogfile"] = "" + db_dict["DataProcessingLOGfileName"] = "" + + # MTZ file + + if os.path.isfile(xtal + ".mtz"): + db_dict["DataProcessingPathToMTZfile"] = os.path.realpath(xtal + ".mtz") + db_dict["DataProcessingMTZfileName"] = xtal + ".mtz" + if not found_logfile: + mtz_info = XChemUtils.mtztools( + xtal + ".mtz" + ).get_information_for_datasource() + db_dict.update(mtz_info) + db_dict["DataCollectionOutcome"] = "success" + else: + db_dict["DataProcessingPathToMTZfile"] = "" + db_dict["DataProcessingMTZfileName"] = "" + + return db_dict + + def sync_dimple_results(self, xtal, db_dict): + # DIMPLE pdb + + if os.path.isfile("dimple.pdb"): + db_dict["DimplePathToPDB"] = os.path.realpath("dimple.pdb") + pdb_info = XChemUtils.parse().PDBheader("dimple.pdb") + db_dict["DimpleRcryst"] = pdb_info["Rcryst"] + db_dict["DimpleRfree"] = pdb_info["Rfree"] + db_dict["DimpleResolutionHigh"] = pdb_info["ResolutionHigh"] + db_dict["DimpleStatus"] = "finished" + else: + db_dict["DimplePathToPDB"] = "" + db_dict["DimpleRcryst"] = "" + db_dict["DimpleRfree"] = "" + db_dict["DimpleResolutionHigh"] = "" + db_dict["DimpleStatus"] = "pending" + + # DIMPLE mtz + + dimple_path = "" + if os.path.isfile("dimple.mtz"): + db_dict["DimplePathToMTZ"] = os.path.realpath("dimple.mtz") + dimple_mtz = db_dict["DimplePathToMTZ"] + dimple_path = dimple_mtz[: dimple_mtz.rfind("/")] + else: + db_dict["DimplePathToMTZ"] = "" + db_dict["DimpleStatus"] = "pending" + + if os.path.isfile( + os.path.join( + dimple_path, + "dimple", + "dimple_rerun_on_selected_file", + "dimple_run_in_progress", + ) + ): + db_dict["DimpleStatus"] = "running" + + # MTZ free file + + if os.path.isfile(xtal + ".free.mtz"): + db_dict["RefinementMTZfree"] = os.path.realpath(xtal + ".free.mtz") + else: + db_dict["RefinementMTZfree"] = "" + os.system("/bin/rm %s.free.mtz 2> /dev/null" % xtal) + if os.path.isfile(os.path.join(dimple_path, "prepared2.mtz")): + os.symlink( + os.path.relpath(os.path.join(dimple_path, "prepared2.mtz")), + xtal + ".free.mtz", + ) + db_dict["RefinementMTZfree"] = os.path.realpath(xtal + ".free.mtz") + elif os.path.isfile(os.path.join(dimple_path, "prepared.mtz")): + os.symlink( + os.path.relpath(os.path.join(dimple_path, "prepared.mtz")), + xtal + ".free.mtz", + ) + db_dict["RefinementMTZfree"] = os.path.realpath(xtal + ".free.mtz") + elif os.path.isfile(os.path.join(dimple_path, "free.mtz")): + os.symlink( + os.path.relpath(os.path.join(dimple_path, "free.mtz")), + xtal + ".free.mtz", + ) + db_dict["RefinementMTZfree"] = os.path.realpath(xtal + ".free.mtz") + + return db_dict + + def sync_compound_information(self, db_dict): + # only update database if SMILES or compoundID field is blank! + + compoundID = db_dict["CompoundCode"] + if compoundID == "None" or compoundID == "": + if os.path.isdir("compound"): + for smiles in glob.glob("compound/*"): + if smiles.endswith("smiles"): + for line in open(smiles): + if len(line.split()) >= 1: + db_dict["CompoundCode"] = smiles[ + smiles.rfind("/") + 1 : smiles.rfind(".") + ] + compoundID = db_dict["CompoundCode"] + break + + if ( + os.path.isfile(compoundID + ".cif") + and os.path.getsize(compoundID + ".cif") > 20 + ): + db_dict["RefinementCIF"] = os.path.realpath(compoundID + ".cif").replace( + os.getcwd() + "/", "" + ) + db_dict["RefinementCIFStatus"] = "restraints generated" + else: + os.system("/bin/rm {0!s}.cif 2> /dev/null".format(compoundID)) + os.system("/bin/rm compound/{0!s}.cif 2> /dev/null".format(compoundID)) + db_dict["RefinementCIF"] = "" + db_dict["RefinementCIFStatus"] = "pending" + + smilesDB = db_dict["CompoundSMILES"] + smiles_found = True + if smilesDB == "None" or smilesDB == "": + smiles_found = False + if os.path.isdir("compound"): + for smiles in glob.glob("compound/*"): + if smiles.endswith("smiles"): + for line in open(smiles): + if len(line.split()) >= 1: + db_dict["CompoundSMILES"] = line.split()[0] + smilesDB = db_dict["CompoundSMILES"] + smiles_found = True + break + + if not smiles_found: + db_dict["RefinementCIFStatus"] = "missing smiles" + + if ( + not os.path.isfile(compoundID + ".pdb") + or os.path.getsize(compoundID + ".pdb") < 20 + ): + os.system("/bin/rm {0!s}.pdb 2> /dev/null".format(compoundID)) + os.system("/bin/rm compound/{0!s}.pdb 2> /dev/null".format(compoundID)) + + if ( + not os.path.isfile(compoundID + ".png") + or os.path.getsize(compoundID + ".png") < 20 + ): + os.system("/bin/rm {0!s}.png 2> /dev/null".format(compoundID)) + os.system("/bin/rm compound/{0!s}.png 2> /dev/null".format(compoundID)) + + return db_dict + + def sync_refinement_results(self, xtal, db_dict): + # REFINE pdb + + if os.path.isfile("refine.pdb"): + db_dict["RefinementPDB_latest"] = os.path.realpath("refine.pdb") + db_dict["RefinementStatus"] = "finished" + pdb_info = XChemUtils.parse().dict_for_datasource_update("refine.pdb") + db_dict.update(pdb_info) + if ( + db_dict["RefinementOutcome"] == "None" + or db_dict["RefinementOutcome"] == "" + ): + db_dict["RefinementOutcome"] = "3 - In Refinement" + elif str(db_dict["RefinementOutcome"]).startswith("1"): + db_dict["RefinementOutcome"] = "3 - In Refinement" + elif str(db_dict["RefinementOutcome"]).startswith("2"): + db_dict["RefinementOutcome"] = "3 - In Refinement" + else: + db_dict["RefinementPDB_latest"] = "" + db_dict["RefinementStatus"] = "pending" + db_dict["RefinementOutcome"] = "1 - Analysis Pending" + os.system("/bin/rm refine.pdb 2> /dev/null") + + if os.path.isfile("REFINEMENT_IN_PROGRESS"): + db_dict["RefinementStatus"] = "running" + + # REFINE bound pdb + + if os.path.isfile("refine.split.bound-state.pdb"): + db_dict["RefinementBoundConformation"] = os.path.realpath( + "refine.split.bound-state.pdb" + ) + else: + db_dict["RefinementBoundConformation"] = "" + + # REFINE mtz + + if os.path.isfile("refine.mtz"): + db_dict["RefinementMTZ_latest"] = os.path.realpath("refine.mtz") + else: + db_dict["RefinementMTZ_latest"] = "" + os.system("/bin/rm refine.mtz 2> /dev/null") + + return db_dict + + def find_apo_structures_for_PanDDA(self, panddaPATH): + # first check if structure is already present in DB and if so if all the + # information concur + + # need to update pandda directory for every exported structure so that + # we know where to look for the pandda.log file that contains the relevant + # information + + # update CrystalName_of_pandda_input in DB + + # in DB: update StructureType field accordingly + + # newer pandda versions seem to have severl copies of pandda.log with names like + # pandda-2016-09-01-2139.log + panddaLog = glob.glob(os.path.join(panddaPATH, "pandda*log")) + panddaLog.sort(key=os.path.getmtime) + + readindApoStructures = False + apoStructures = [] + apoStructureDict = {} + apoString = "" + for files in panddaLog: + for line in open(files): + if "No Statistical Maps Found:" in line: + readindApoStructures = True + if readindApoStructures: + if "Pickling Object: processed_datasets" in line: + if line.split() >= 2: + # e.g. line.split() -> + # ['Pickling', + # 'Object:', + # 'processed_datasets/NUDT22A-x0055/pickles/dataset.pickle'] + xtal = line.split()[2].split("/")[1] + if os.path.isfile( + os.path.join( + panddaPATH, + "processed_datasets", + xtal, + xtal + "-pandda-input.pdb", + ) + ): + apoStructures.append(xtal) + apoString += xtal + ";" + if ( + "Pre-existing statistical maps (from previous runs) have been found" + " and will be reused:" in line + ): + readindApoStructures = False + apoStructureDict[panddaPATH] = apoStructures + + return apoString[:-1] + + def sync_pandda_table_NEW(self): + progress_step = 1 + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + # also need to update PANDDA table... + pandda_models = self.db.execute_statement( + "select CrystalName,PANDDA_site_index,PANDDA_site_event_index," + "PANDDA_site_x,PANDDA_site_y,PANDDA_site_z,PANDDApath,ApoStructures" + " from panddaTable" + ) + if len(pandda_models) > 0: + progress_step = 100 / float(len(pandda_models)) + else: + self.Logfile.warning("panddaTable seems to be empty!") + + if pandda_models: + for entry in pandda_models: + db_pandda_dict = {} + xtal = entry[0] + site_index = entry[1] + event_index = entry[2] + panddaPATH = entry[6] + apoStructures = entry[7] + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "checking {0!s} -> site {1!s} -> event {2!s} ".format( + xtal, site_index, event_index + ), + ) + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + progress += progress_step + + try: + event_x = float(str(entry[3])) + event_y = float(str(entry[4])) + event_z = float(str(entry[5])) + except ValueError: + pass + + # do not update pandda path since this one is updated during pandda + # export! instead try to get apo semi-colon separated list of apo + # structures that were used to calculate event maps; but only if field + # is blank! + if str(apoStructures) == "None" or apoStructures == "": + if panddaPATH != "None" or panddaPATH != "": + self.Logfile.insert( + "trying to find which apo structures were used to calculate" + " the event maps in " + panddaPATH + ) + db_pandda_dict[ + "ApoStructures" + ] = self.find_apo_structures_for_PanDDA(panddaPATH) + else: + self.Logfile.insert( + "pandda path for " + xtal + " is empty in database" + ) + + # event map + + found_event_map = False + db_pandda_dict["PANDDA_site_event_map"] = "" + for file in glob.glob( + os.path.join(self.initial_model_directory, xtal, "*ccp4") + ): + filename = file[file.rfind("/") + 1 :] + if filename.startswith( + xtal + "-event_" + event_index + ) and filename.endswith("map.native.ccp4"): + event_map = file + db_pandda_dict["PANDDA_site_event_map"] = os.path.realpath( + event_map + ) + found_event_map = True + break + if not found_event_map: + db_pandda_dict["PANDDA_site_event_map"] = "" + + db_pandda_dict["PANDDA_site_initial_model"] = "" + for file in glob.glob( + os.path.join(self.initial_model_directory, xtal, "*pdb") + ): + filename = file[file.rfind("/") + 1 :] + if filename.endswith("-ensemble-model.pdb"): + db_pandda_dict["PANDDA_site_initial_model"] = os.path.realpath( + file + ).replace(os.getcwd() + "/", "") + break + + db_pandda_dict["PANDDA_site_initial_mtz"] = "" + for file in glob.glob( + os.path.join(self.initial_model_directory, xtal, "*mtz") + ): + filename = file[file.rfind("/") + 1 :] + if filename.endswith("pandda-input.mtz"): + db_pandda_dict["PANDDA_site_initial_mtz"] = os.path.realpath( + file + ).replace(os.getcwd() + "/", "") + break + + db_pandda_dict["PANDDA_site_ligand_resname"] = "" + db_pandda_dict["PANDDA_site_ligand_chain"] = "" + db_pandda_dict["PANDDA_site_ligand_sequence_number"] = "" + db_pandda_dict["PANDDA_site_ligand_altLoc"] = "" + db_pandda_dict["PANDDA_site_ligand_placed"] = "False" + db_pandda_dict["PANDDA_site_spider_plot"] = "" + db_pandda_dict["PANDDA_site_ligand_id"] = "" + + db_pandda_dict["PANDDA_site_occupancy"] = "" + db_pandda_dict["PANDDA_site_B_average"] = "" + db_pandda_dict["PANDDA_site_B_ratio_residue_surroundings"] = "" + db_pandda_dict["PANDDA_site_rmsd"] = "" + db_pandda_dict["PANDDA_site_RSCC"] = "" + db_pandda_dict["PANDDA_site_RSR"] = "" + db_pandda_dict["PANDDA_site_RSZD"] = "" + + if os.path.isfile( + os.path.join(self.initial_model_directory, xtal, "refine.pdb") + ): + ligands_in_file = XChemUtils.pdbtools( + os.path.join(self.initial_model_directory, xtal, "refine.pdb") + ).find_xce_ligand_details() + if not ligands_in_file: + self.Logfile.warning( + "{0!s}: could not find any ligands in refine.pdb".format( + xtal + ) + ) + continue + else: + self.Logfile.insert( + "{0!s}: found the following ligands in" + " refine.pdb: {1!s}".format(xtal, str(ligands_in_file)) + ) + + distanceList = [] + for ligand in ligands_in_file: + residue_name = ligand[0] + residue_chain = ligand[1] + residue_number = ligand[2] + residue_altLoc = ligand[3] + residue_xyz = XChemUtils.pdbtools( + os.path.join( + self.initial_model_directory, xtal, "refine.pdb" + ) + ).get_center_of_gravity_of_residue_ish( + residue_chain, residue_number + ) + distance = XChemUtils.calculate_distance_between_coordinates( + residue_xyz[0], + residue_xyz[1], + residue_xyz[2], + event_x, + event_y, + event_z, + ) + distanceList.append( + [ + distance, + residue_name, + residue_chain, + residue_number, + residue_altLoc, + ] + ) + self.Logfile.insert( + "{0!s}: calculating distance between event and ligand" + " ({1!s} {2!s} {3!s}): {4!s}".format( + xtal, + residue_name, + residue_chain, + residue_number, + str(distance), + ) + ) + + # now take the ligand that is closest to the event + try: + smallestDistance = min(distanceList, key=lambda x: x[0]) + except ValueError: + self.Logfile.error( + "could not determine smallest distance between current" + " ligand pandda events" + ) + continue + distance = smallestDistance[0] + residue_name = smallestDistance[1] + residue_chain = smallestDistance[2] + residue_number = smallestDistance[3] + residue_altLoc = smallestDistance[4] + self.Logfile.insert( + "{0!s}: ligand with the shorted distance ({1!s}A) to the" + " current event (id: {2!s}): {3!s} {4!s} {5!s} {6!s}".format( + xtal, + str(distance), + event_index, + residue_name, + residue_chain, + residue_number, + residue_altLoc, + ) + ) + db_pandda_dict["PANDDA_site_ligand_resname"] = residue_name + db_pandda_dict["PANDDA_site_ligand_chain"] = residue_chain + db_pandda_dict[ + "PANDDA_site_ligand_sequence_number" + ] = residue_number + db_pandda_dict["PANDDA_site_ligand_altLoc"] = residue_altLoc + db_pandda_dict["PANDDA_site_ligand_placed"] = "True" + db_pandda_dict["PANDDA_site_ligand_id"] = ( + residue_name + "-" + residue_chain + "-" + residue_number + ) + + if xtal + "/Refine_" in os.path.realpath( + os.path.join(self.initial_model_directory, xtal, "refine.pdb") + ): + tmp = os.path.realpath( + os.path.join( + self.initial_model_directory, xtal, "refine.pdb" + ) + ) + spider_plot = os.path.join( + tmp[: tmp.rfind("/")], + "residue_plots", + residue_chain + "-" + residue_number + ".png", + ).replace(" ", "") + if os.path.isfile(spider_plot): + db_pandda_dict[ + "PANDDA_site_spider_plot" + ] = os.path.realpath(spider_plot) + if os.path.isfile( + os.path.join(tmp[: tmp.rfind("/")], "residue_scores.csv") + ): + with open( + os.path.join( + tmp[: tmp.rfind("/")], "residue_scores.csv" + ), + "rb", + ) as csv_import: + csv_dict = csv.DictReader(csv_import) + for i, line in enumerate(csv_dict): + residueNameChainNumber = line[""] + if ( + residueNameChainNumber + == residue_chain + "-" + residue_number + ): + db_pandda_dict["PANDDA_site_occupancy"] = line[ + "Occupancy" + ] + db_pandda_dict["PANDDA_site_B_average"] = line[ + "Average B-factor (Residue)" + ] + db_pandda_dict[ + "PANDDA_site_B_ratio_residue_surroundings" + ] = line["Surroundings B-factor Ratio"] + db_pandda_dict["PANDDA_site_rmsd"] = line[ + "Model RMSD" + ] + db_pandda_dict["PANDDA_site_RSCC"] = line[ + "RSCC" + ] + db_pandda_dict["PANDDA_site_RSR"] = line["RSR"] + db_pandda_dict["PANDDA_site_RSZD"] = line[ + "RSZD" + ] + if db_pandda_dict != {}: + self.db.update_site_event_panddaTable( + xtal, site_index, event_index, db_pandda_dict + ) + self.Logfile.insert( + "updating panddaTable for" + " xtal: {0!s}, site: {1!s}, event: {2!s}".format( + xtal, site_index, event_index + ) + ) + self.Logfile.insert("-> panddaDict: " + str(db_pandda_dict)) + + +class create_png_and_cif_of_compound(QtCore.QThread): + def __init__( + self, + external_software, + initial_model_directory, + compound_list, + database_directory, + data_source_file, + todo, + ccp4_scratch_directory, + xce_logfile, + max_queue_jobs, + restraints_program, + slurm_token, + ): + QtCore.QThread.__init__(self) + self.external_software = external_software + self.initial_model_directory = initial_model_directory + self.compound_list = compound_list + self.database_directory = database_directory + self.data_source_file = data_source_file + self.todo = todo + self.ccp4_scratch_directory = ccp4_scratch_directory + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.max_queue_jobs = max_queue_jobs + self.db = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ) + self.restraints_program = restraints_program + self.slurm_token = slurm_token + + def run(self): + # first remove all ACEDRG input scripts in ccp4_scratch directory + self.Logfile.insert( + "removing all xce_acedrg scripts from " + self.ccp4_scratch_directory + ) + os.chdir(self.ccp4_scratch_directory) + os.system("/bin/rm -f xce_acedrg*") + + progress_step = 100 / float(len(self.compound_list)) + progress = 0 + counter = 1 + for item in self.compound_list: + sampleID = item[0] + compoundID = item[1] + sm = item[2] + # if counterions are present, split and take the longest string in list + smiles = max(sm.split("."), key=len) + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "creating ACEDRG shell script for " + sampleID, + ) + if compoundID == "" or compoundID is None: + compoundID = "compound" + + if not os.path.isdir(os.path.join(self.initial_model_directory, sampleID)): + os.mkdir(os.path.join(self.initial_model_directory, sampleID)) + + if self.todo == "ALL" or self.todo == "SELECTED": + # remove symbolic links if present + if os.path.isfile( + os.path.join( + self.initial_model_directory, + sampleID, + compoundID.replace(" ", "") + ".pdb", + ) + ): + os.system( + "/bin/rm " + + os.path.join( + self.initial_model_directory, + sampleID, + compoundID.replace(" ", "") + ".pdb", + ) + ) + if os.path.isfile( + os.path.join( + self.initial_model_directory, + sampleID, + compoundID.replace(" ", "") + ".png", + ) + ): + os.system( + "/bin/rm " + + os.path.join( + self.initial_model_directory, + sampleID, + compoundID.replace(" ", "") + ".png", + ) + ) + if os.path.isdir( + os.path.join(self.initial_model_directory, sampleID, "compound") + ): + os.system( + "/bin/rm -fr " + + os.path.join( + self.initial_model_directory, sampleID, "compound" + ) + ) + db_dict = {"RefinementCIFStatus": "pending"} + self.Logfile.insert( + "{0!s}: removed compound directory and all its contents".format( + sampleID + ) + ) + self.Logfile.insert( + "{0!s}: setting RefinementCIFStatus flag to started".format( + sampleID + ) + ) + self.db.update_data_source(sampleID, db_dict) + + # create 'compound' directory if not present + if not os.path.isdir( + os.path.join(self.initial_model_directory, sampleID, "compound") + ): + os.mkdir( + os.path.join(self.initial_model_directory, sampleID, "compound") + ) + + # create text file which contains the smiles string + if not os.path.isfile( + os.path.join( + self.initial_model_directory, + sampleID, + "compound", + compoundID + ".smiles", + ) + ): + os.chdir( + os.path.join(self.initial_model_directory, sampleID, "compound") + ) + f = open(compoundID + ".smiles", "w") + f.write(smiles) + f.close() + + if ( + not os.path.isfile( + os.path.join( + self.initial_model_directory, + sampleID, + compoundID.replace(" ", "") + ".cif", + ) + ) + or self.todo == "SELECTED" + ): + os.chdir(os.path.join(self.initial_model_directory, sampleID)) + os.system("/bin/rm -f %s*" % compoundID.replace(" ", "")) + os.chdir( + os.path.join(self.initial_model_directory, sampleID, "compound") + ) + + XChemUtils.helpers().make_png( + self.initial_model_directory, + sampleID, + compoundID, + smiles, + self.external_software, + self.database_directory, + self.data_source_file, + self.ccp4_scratch_directory, + counter, + self.xce_logfile, + self.restraints_program, + ) + counter += 1 + + db_dict = { + "RefinementCIFprogram": self.restraints_program, + "RefinementCIFStatus": "started", + } + self.Logfile.insert( + "{0!s}: setting RefinementCIFStatus flag to started".format( + sampleID + ) + ) + self.db.update_data_source(sampleID, db_dict) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + # submit array job at Diamond + self.Logfile.insert( + "created input scripts for " + + str(counter) + + " ACEDRG jobs in " + + self.ccp4_scratch_directory + ) + os.chdir(self.ccp4_scratch_directory) + self.Logfile.insert("changing directory to " + self.ccp4_scratch_directory) + if counter > 1: + Cmds = ( + "#!/bin/bash\n" + + ". /etc/profile.d/modules.sh\n" + + "./xce_{}_$SLURM_ARRAY_TASK_ID.sh\n".format(self.restraints_program) + ) + f = open("%s_master.sh" % self.restraints_program, "w") + f.write(Cmds) + f.close() + slurm.submit_cluster_job( + str(self.restraints_program), + "{!s}_master.sh".format(self.restraints_program), + self.xce_logfile, + self.slurm_token, + array="0-{}".format(counter), + ) + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + +class fit_ligands(QtCore.QThread): + def __init__( + self, + external_software, + initial_model_directory, + compound_list, + database_directory, + data_source_file, + ccp4_scratch_directory, + xce_logfile, + max_queue_jobs, + slurm_token, + ): + QtCore.QThread.__init__(self) + self.external_software = external_software + self.initial_model_directory = initial_model_directory + self.compound_list = compound_list + self.database_directory = database_directory + self.data_source_file = data_source_file + self.ccp4_scratch_directory = ccp4_scratch_directory + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.max_queue_jobs = max_queue_jobs + self.slurm_token = slurm_token + self.db = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ) + self.n = 1 + + def prepareInput(self, cmd, ligList): + for cif in ligList: + cmd += ( + "rhofit -m ../init.mtz -p ../init.pdb -l ../compound/%s.cif" + " -scanchirals -d %s_rhofit\n" % (cif, cif) + ) + cmd += ( + "phenix.ligandfit data=../init.mtz" + " model=../init.pdb ligand=../compound/%s.cif clean_up=True\n" % cif + ) + cmd += "/bin/mv LigandFit_run_1_ %s_phenix\n" % cif + cmd += "/bin/rm -fr PDS\n\n" + return cmd + + def get_header(self, sampleID): + module = "" + if os.path.isdir("/dls"): + module = "module load phenix/1.20\n" + module += "module load buster/20240123\n" + + cmd = ( + 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"\n' + "\n" + "cd %s\n" + % os.path.join(self.initial_model_directory, sampleID, "autofit_ligand") + + "\n" + + module + ) + + return cmd + + def get_footer(self, cmd, sampleID, compoundID): + cmd += ( + "$CCP4/bin/ccp4-python" + " $XChemExplorer_DIR/xce/helpers/" + "find_best_fitting_ligand.py {0!s} {1!s} {2!s}".format( + compoundID.replace(" ", ""), + os.path.join(self.initial_model_directory, sampleID), + os.path.join(self.database_directory, self.data_source_file), + ) + ) + return cmd + + def run(self): + # first remove all ACEDRG input scripts in ccp4_scratch directory + self.Logfile.insert( + "removing all xce_fit_ligands scripts from " + self.ccp4_scratch_directory + ) + os.chdir(self.ccp4_scratch_directory) + os.system("/bin/rm -f xce_autofit_ligand*") + + progress_step = 100 / float(len(self.compound_list)) + progress = 0 + for item in self.compound_list: + sampleID = item[0] + compoundID = item[1] + + if os.path.isdir( + os.path.join(self.initial_model_directory, sampleID, "autofit_ligand") + ): + os.system( + "/bin/rm -fr " + + os.path.join( + self.initial_model_directory, sampleID, "autofit_ligand" + ) + ) + os.mkdir( + os.path.join(self.initial_model_directory, sampleID, "autofit_ligand") + ) + + # find ligands to fit (there might be more than one in case of stereoisomers + ligList = [] + for file in glob.glob( + os.path.join( + self.initial_model_directory, + sampleID, + "compound", + compoundID + "*.cif", + ) + ): + cif = file[file.rfind("/") + 1 :].replace(".cif", "") + if "with_H" in cif: + continue + else: + ligList.append(cif) + + if ligList != []: + cmd = self.get_header(sampleID) + cmd = self.prepareInput(cmd, ligList) + cmd = self.get_footer(cmd, sampleID, compoundID) + self.write_script(cmd) + self.run_script() + self.n += 1 + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + def write_script(self, cmd): + os.chdir(self.ccp4_scratch_directory) + f = open("xce_autofit_ligand_{0!s}.sh".format(str(self.n)), "w") + f.write(cmd) + f.close() + os.system("chmod +x xce_autofit_ligand_{0!s}.sh".format(str(self.n))) + + def run_script(self): + # submit job + self.Logfile.insert( + "created input scripts for " + + str(self.n) + + " in " + + self.ccp4_scratch_directory + ) + os.chdir(self.ccp4_scratch_directory) + Cmds = ( + "#!/bin/bash\n" + + ". /etc/profile.d/modules.sh\n" + + "./xce_autofit_ligand_$SLURM_ARRAY_TASK_ID.sh\n" + ) + f = open("autofit_ligand_master.sh", "w") + f.write(Cmds) + f.close() + slurm.submit_cluster_job( + "xce_autofit_ligand_master", + "autofit_ligand_master.sh", + self.xce_logfile, + self.slurm_token, + array="1-{!s}".format(self.n - 1), + ) + + +class merge_cif_files(QtCore.QThread): + def __init__( + self, initial_model_directory, xce_logfile, second_cif_file, compound_list, todo + ): + QtCore.QThread.__init__(self) + self.initial_model_directory = initial_model_directory + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.second_cif_file = second_cif_file + self.compound_list = compound_list + self.todo = todo + + def run(self): + progress_step = 100 / float(len(self.compound_list)) + progress = 0 + + for item in self.compound_list: + sampleID = item[0] + compoundID = item[1] + + if os.path.isfile( + os.path.join( + self.initial_model_directory, + sampleID, + "compound", + compoundID + ".cif", + ) + ): + self.Logfile.insert( + "%s: found %s.cif file in compound sub-directory" + % (sampleID, compoundID) + ) + else: + self.Logfile.error( + "%s: %s.cif file does not exist in compound sub-directory;" + " skipping..." % (sampleID, compoundID) + ) + continue + + os.chdir(os.path.join(self.initial_model_directory, sampleID)) + if os.path.isfile( + os.path.join( + self.initial_model_directory, sampleID, compoundID + ".cif" + ) + ): + self.Logfile.warning( + "%s: removing symbolic link to (or file) %s.cif" + " from sample directory" % (sampleID, compoundID) + ) + os.system("/bin/rm %s.cif 2> /dev/null" % compoundID) + + if self.todo == "merge": + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + sampleID + " merging CIF files", + ) + + self.run_libcheck(sampleID, compoundID) + + elif self.todo == "restore": + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + sampleID + " restoring original CIF file", + ) + self.Logfile.insert( + "%s: restoring symbolic link -> ln -s compound/%s.cif ." + % (sampleID, compoundID) + ) + os.system("ln -s compound/%s.cif ." % compoundID) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.emit(QtCore.SIGNAL("finished()")) + + def run_libcheck(self, sampleID, compoundID): + cmd = ( + "#!/bin/bash\n" + "\n" + ". /etc/profile.d/modules.sh\n" + "$CCP4/bin/libcheck << eof \n" + "_Y\n" + "_FILE_L compound/%s.cif\n" % compoundID + + "_FILE_L2 " + + self.second_cif_file + + "\n" + "_FILE_O " + compoundID + ".cif\n" + "_END\n" + "eof\n" + ) + self.Logfile.insert( + "%s: running libcheck with the following input:\n%s" % (sampleID, cmd) + ) + os.system(cmd) + if os.path.isfile(compoundID + ".cif.lib"): + self.Logfile.insert("%s: merged CIF file successfully created" % sampleID) + os.system("/bin/mv %s %s" % (compoundID + ".cif.lib", compoundID + ".cif")) + else: + self.Logfile.error("%s: could not create merged CIF file" % sampleID) + self.Logfile.warning( + "%s: will re-create symbolic links to original restraints file" + % sampleID + ) + os.system("ln -s compound/%s.cif ." % compoundID) + + +class run_dimple_on_all_autoprocessing_files_new(QtCore.QThread): + def __init__( + self, + sample_list, + initial_model_directory, + external_software, + ccp4_scratch_directory, + database_directory, + data_source_file, + max_queue_jobs, + xce_logfile, + dimple_twin_mode, + pipeline, + slurm_token, + ): + QtCore.QThread.__init__(self) + self.sample_list = sample_list + self.initial_model_directory = initial_model_directory + self.external_software = external_software + self.ccp4_scratch_directory = ccp4_scratch_directory + self.database_directory = database_directory + self.data_source_file = data_source_file + self.db = XChemDB.data_source( + os.path.join(self.database_directory, self.data_source_file) + ) + self.max_queue_jobs = max_queue_jobs + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.pipeline = pipeline + self.dimple_twin_mode = dimple_twin_mode + self.slurm_token = slurm_token + + self.n = 1 + + self.Logfile.insert( + "running initial refinement with the following pipeline: " + self.pipeline + ) + + def run(self): + progress_step = 1 + if len(self.sample_list) != 0: + progress_step = 100 / float(len(self.sample_list)) + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + os.chdir(self.ccp4_scratch_directory) + os.system("/bin/rm -f xce_{0!s}*sh".format(self.pipeline)) + + for item in sorted(self.sample_list): + xtal = item[0] + visit_run_autoproc = item[1] + mtzin = item[2] + ref_pdb = item[3] + ref_mtz = item[4] + ref_cif = item[5] + + if "dimple_rerun_on_selected_file" in visit_run_autoproc: + if self.pipeline == "dimple": + twin = self.prepare_dimple_shell_script( + xtal, visit_run_autoproc, mtzin, ref_pdb, ref_mtz, ref_cif + ) + elif self.pipeline == "pipedream": + twin = self.prepare_pipedream_shell_script( + xtal, visit_run_autoproc, mtzin, ref_pdb, ref_mtz, ref_cif + ) + elif self.pipeline == "phenix.ligand_pipeline": + twin = self.prepare_phenix_ligand_pipeline_shell_script( + xtal, visit_run_autoproc, mtzin, ref_pdb, ref_mtz, ref_cif + ) + else: + twin = self.prepare_dimple_shell_script( + xtal, visit_run_autoproc, mtzin, ref_pdb, ref_mtz, ref_cif + ) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.run_script(twin) + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + def prepare_phenix_ligand_pipeline_shell_script( + self, xtal, visit_run_autoproc, mtzin, ref_pdb, ref_mtz, ref_cif + ): + # check if reference mtzfile has an Rfree column; if not, then ignore + # DIMPLE assumes an Rfree column and barfs if it is not present + # note: ref_mtz looks like this: ref mtz -R reference.mtz + + if not os.path.isdir(os.path.join(self.initial_model_directory, xtal)): + os.mkdir(os.path.join(self.initial_model_directory, xtal)) + os.chdir(os.path.join(self.initial_model_directory, xtal)) + if os.path.isdir( + os.path.join(self.initial_model_directory, xtal, "phenix.ligand_pipeline") + ): + os.system("/bin/rm -fr phenix.ligand_pipeline") + os.mkdir( + os.path.join(self.initial_model_directory, xtal, "phenix.ligand_pipeline") + ) + os.system("touch phenix.ligand_pipeline_run_in_progress") + + if "bash" in os.getenv("SHELL"): + ccp4_scratch = "export CCP4_SCR=" + self.ccp4_scratch_directory + "\n" + else: + ccp4_scratch = "" + + if os.path.isdir("/dls"): + ccp4_scratch += "module load phenix/1.20\n" + ccp4_scratch += "module load ccp4/7.1.018\n" + + mtz_column_list = XChemUtils.mtztools(mtzin).get_all_columns_as_list() + rfree = "" + if "FreeR_flag" in mtz_column_list: + rfree = ' xray_data.r_free_flags.label="FreeR_flag"' + + Cmds = ( + 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"\n' + "\n" + "cd %s\n" + % os.path.join(self.initial_model_directory, xtal, "phenix.ligand_pipeline") + + "\n" + "module load global/cluster\n" + "module load phenix/1.20\n" + "module load buster/20240123\n" + "\n" + ccp4_scratch + "\n" + "$CCP4/bin/ccp4-python" + " $XChemExplorer_DIR/xce/helpers/update_status_flag.py %s %s %s %s\n" + % ( + os.path.join(self.database_directory, self.data_source_file), + xtal, + "DimpleStatus", + "running", + ) + + "\n" + "phenix.ligand_pipeline %s %s" % (ref_pdb, mtzin) + " mr=False" + " ligand_copies=0" + " build=False" + " prune=False" + " remove_waters=False" + " stop_if_r_free_greater_than=0.4" + " update_waters=False" + rfree + " build_hydrogens=False\n" + "\n" + "fft hklin pipeline_1/refine_final.mtz mapout 2fofc.map << EOF\n" + " labin F1=2FOFCWT_filled PHI=PH2FOFCWT\n" + "EOF\n" + "\n" + "fft hklin pipeline_1/refine_final.mtz mapout fofc.map << EOF\n" + " labin F1=FOFCWT PHI=PHFOFCWT\n" + "EOF\n" + "\n" + "cd %s\n" % os.path.join(self.initial_model_directory, xtal) + "\n" + "/bin/rm phenix.ligand_pipeline.pdb\n" + "/bin/rm phenix.ligand_pipeline.mtz\n" + "\n" + "ln -s phenix.ligand_pipeline/pipeline_1/refine_final.pdb" + " phenix.ligand_pipeline.pdb\n" + "ln -s phenix.ligand_pipeline/pipeline_1/refine_final.mtz" + " phenix.ligand_pipeline.mtz\n" + "\n" + "/bin/rm init.pdb\n" + "/bin/rm init.mtz\n" + "\n" + "ln -s phenix.ligand_pipeline.pdb init.pdb\n" + "ln -s phenix.ligand_pipeline.mtz init.mtz\n" + "\n" + "/bin/rm 2fofc.map\n" + "/bin/rm fofc.map\n" + "\n" + "ln -s phenix.ligand_pipeline/2fofc.map .\n" + "ln -s phenix.ligand_pipeline/fofc.map .\n" + "\n" + "$CCP4/bin/ccp4-python " + + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "update_data_source_for_new_dimple_pdb.py", + ) + + " {0!s} {1!s} {2!s}\n".format( + os.path.join(self.database_directory, self.data_source_file), + xtal, + self.initial_model_directory, + ) + + "\n" + "/bin/rm phenix.ligand_pipeline_run_in_progress\n" + ) + + os.chdir(self.ccp4_scratch_directory) + f = open("xce_{0!s}_{1!s}.sh".format(self.pipeline, str(self.n)), "w") + f.write(Cmds) + f.close() + os.system("chmod +x xce_{0!s}_{1!s}.sh".format(self.pipeline, str(self.n))) + self.n += 1 + db_dict = {"DimpleStatus": "started"} + self.Logfile.insert( + "{0!s}: setting DataProcessingStatus flag to started".format(xtal) + ) + self.db.update_data_source(xtal, db_dict) + twin = "" + return twin + + def prepare_pipedream_shell_script( + self, xtal, visit_run_autoproc, mtzin, ref_pdb, ref_mtz, ref_cif + ): + if not os.path.isdir(os.path.join(self.initial_model_directory, xtal)): + os.mkdir(os.path.join(self.initial_model_directory, xtal)) + if os.path.isdir(os.path.join(self.initial_model_directory, xtal, "pipedream")): + os.chdir(os.path.join(self.initial_model_directory, xtal)) + os.system("/bin/rm -fr pipedream") + os.mkdir(os.path.join(self.initial_model_directory, xtal, "pipedream")) + os.system("touch pipedream_run_in_progress") + + if "bash" in os.getenv("SHELL"): + ccp4_scratch = "export CCP4_SCR=" + self.ccp4_scratch_directory + "\n" + else: + ccp4_scratch = "" + + if os.path.isdir("/dls"): + ccp4_scratch += "module load buster/20240123\n" + ccp4_scratch += "module load ccp4/7.1.018\n" + + if os.path.isfile(ref_mtz): + hklref_line = " -hklref {0!s}".format(ref_mtz) + else: + hklref_line = " -nofreeref" + + Cmds = ( + 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"\n' + "\n" + "cd %s\n" % os.path.join(self.initial_model_directory, xtal, "pipedream") + + "\n" + "module load global/cluster\n" + "module load phenix/1.20\n" + "module load buster/20240123\n" + "\n" + ccp4_scratch + "\n" + "$CCP4/bin/ccp4-python $XChemExplorer_DIR/xce/helpers/update_status_flag.py" + " %s %s %s %s\n" + % ( + os.path.join(self.database_directory, self.data_source_file), + xtal, + "DimpleStatus", + "running", + ) + + "\n" + "pointless hklin {0!s} xyzin {1!s} hklout pointless.mtz >" + " pointless.log\n".format(mtzin, ref_pdb) + "\n" + "pipedream " + " -d pipedreamDir" + " -xyzin %s" % ref_pdb + hklref_line + " -hklin pointless.mtz" + " -keepwater\n" + "\n" + "fft hklin pipedreamDir/refine/refine.mtz mapout 2fofc.map << EOF\n" + " labin F1=2FOFCWT PHI=PH2FOFCWT\n" + "EOF\n" + "\n" + "fft hklin pipedreamDir/refine/refine.mtz mapout fofc.map << EOF\n" + " labin F1=FOFCWT PHI=PHFOFCWT\n" + "EOF\n" + "\n" + "cd %s\n" % os.path.join(self.initial_model_directory, xtal) + "\n" + "/bin/rm pipedream.pdb\n" + "/bin/rm pipedream.mtz\n" + "\n" + "ln -s pipedream/pipedreamDir/refine/refine.pdb pipedream.pdb\n" + "ln -s pipedream/pipedreamDir/refine/refine.mtz pipedream.mtz\n" + "\n" + "/bin/rm init.pdb\n" + "/bin/rm init.mtz\n" + "\n" + "ln -s pipedream.pdb init.pdb\n" + "ln -s pipedream.mtz init.mtz\n" + "\n" + "/bin/rm 2fofc.map\n" + "/bin/rm fofc.map\n" + "\n" + "ln -s pipedream/2fofc.map .\n" + "ln -s pipedream/fofc.map .\n" + "\n" + "$CCP4/libexec/python " + + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "update_data_source_for_new_dimple_pdb.py", + ) + + " {0!s} {1!s} {2!s}\n".format( + os.path.join(self.database_directory, self.data_source_file), + xtal, + self.initial_model_directory, + ) + + "\n" + "/bin/rm pipedream_run_in_progress\n" + ) + + os.chdir(self.ccp4_scratch_directory) + f = open("xce_{0!s}_{1!s}.sh".format(self.pipeline, str(self.n)), "w") + f.write(Cmds) + f.close() + os.system("chmod +x xce_{0!s}_{1!s}.sh".format(self.pipeline, str(self.n))) + self.n += 1 + db_dict = {"DimpleStatus": "started"} + self.Logfile.insert( + "{0!s}: setting DataProcessingStatus flag to started".format(xtal) + ) + self.db.update_data_source(xtal, db_dict) + twin = "" + return twin + + def prepare_dimple_shell_script( + self, xtal, visit_run_autoproc, mtzin, ref_pdb, ref_mtz, ref_cif + ): + # check if reference mtzfile has an Rfree column; if not, then ignore + # DIMPLE assumes an Rfree column and barfs if it is not present + # note: ref_mtz looks like this: ref mtz -R reference.mtz + if os.path.isfile(ref_mtz): + mtz_column_dict = XChemUtils.mtztools(ref_mtz).get_all_columns_as_dict() + if "FreeR_flag" not in mtz_column_dict["RFREE"]: + self.Logfile.insert( + "cannot find FreeR_flag in reference mtz file: {0!s} ->" + " ignoring reference mtzfile!!!".format(ref_mtz) + ) + ref_mtz = "" + if mtz_column_dict["RFREE"]: + self.Logfile.insert( + "found Rfree set with other column name though: {0!s}".format( + str(mtz_column_dict["RFREE"]) + ) + ) + self.Logfile.insert( + "try renaming Rfree column to FreeR_flag with CAD!" + ) + + db_dict = {"DimpleReferencePDB": ref_pdb} + self.db.update_data_source(xtal, db_dict) + + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "creating input script for " + xtal + " in " + visit_run_autoproc, + ) + + if not os.path.isdir(os.path.join(self.initial_model_directory, xtal)): + os.mkdir(os.path.join(self.initial_model_directory, xtal)) + os.chdir(os.path.join(self.initial_model_directory, xtal)) + + twin = "" + twinRefmac = "" + if self.dimple_twin_mode: + twinRefmac = "--refmac-key 'TWIN'" + twin = "_twin" + if os.path.isdir( + os.path.join(self.initial_model_directory, xtal, "dimple_twin") + ): + os.system("/bin/rm -fr dimple_twin") + os.mkdir(os.path.join(self.initial_model_directory, xtal, "dimple_twin")) + os.system("touch dimple_twin_run_in_progress") + else: + if os.path.isdir( + os.path.join(self.initial_model_directory, xtal, "dimple") + ): + os.system("/bin/rm -fr dimple") + os.mkdir(os.path.join(self.initial_model_directory, xtal, "dimple")) + os.system("touch dimple_run_in_progress") + os.system("/bin/rm final.mtz 2> /dev/null") + os.system("/bin/rm final.pdb 2> /dev/null") + + if "bash" in os.getenv("SHELL"): + ccp4_scratch = "export CCP4_SCR=" + self.ccp4_scratch_directory + "\n" + else: + ccp4_scratch = "" + + if os.path.isdir("/dls"): + ccp4_scratch += "module load ccp4/7.1.018\n" + + hkl = any_reflection_file(file_name=mtzin) + miller_arrays = hkl.as_miller_arrays() + mtzFile = miller_arrays[0] + + if mtzFile.space_group_info().symbol_and_number() == "R 3 :H (No. 146)": + symNoAbsence = "H3" + elif mtzFile.space_group_info().symbol_and_number() == "R 3 2 :H (No. 155)": + symNoAbsence = "H32" + else: + symNoAbsence = ( + str( + [ + x[0] + for x in str( + mtzFile.space_group_info().symbol_and_number().split("(")[0] + ).split() + ] + ) + .replace("[", "") + .replace("]", "") + .replace("'", "") + .replace(",", "") + .replace(" ", "") + ) + + Cmds = ( + 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"\n' + "\n" + "cd %s\n" + % os.path.join(self.initial_model_directory, xtal, "dimple%s" % twin) + + "\n" + "module load global/cluster\n" + "module load phenix/1.20\n" + "module load buster/20240123\n" + "\n" + ccp4_scratch + "\n" + "$CCP4/bin/ccp4-python $XChemExplorer_DIR/xce/helpers/update_status_flag.py" + " %s %s %s %s\n" + % ( + os.path.join(self.database_directory, self.data_source_file), + xtal, + "DimpleStatus", + "running", + ) + + "\n" + "cd %s\n" + % os.path.join(self.initial_model_directory, xtal, "dimple%s" % twin) + + "\n" + "unique hklout unique.mtz << eof\n" + " cell %s\n" + % str([round(float(i), 2) for i in mtzFile.unit_cell().parameters()]) + .replace("[", "") + .replace("]", "") + + " symmetry %s\n" % symNoAbsence + + " resolution %s\n" % str(round(float(mtzFile.d_min()), 3)) + + "eof\n" + "\n" + "\n" + "sftools << eof > sftools.log\n" + " read unique.mtz\n" + " calc col F = 10.0\n" + " calc col SIGF = 1.0\n" + " write sftools.mtz\n" + "eof\n" + "\n" + "cad hklin1 sftools.mtz hklin2 %s hklout %s.999A.mtz << eof\n" + % (mtzin, xtal) + + " monitor BRIEF\n" + " labin file 1 E1=F E2=SIGF\n" + " labout file 1 E1=F_unique E2=SIGF_unique\n" + " labin file 2 ALL\n" + " resolution file 1 999.0 %s\n" % str(round(float(mtzFile.d_min()), 2)) + + "eof\n" + "\n" + "pointless hklin %s.999A.mtz hklout %s.999A.reind.mtz xyzin %s << eof >" + " pointless.reind.log\n" % (xtal, xtal, ref_pdb) + " tolerance 5\n" + "eof\n" + "\n" + "dimple --no-cleanup %s.999A.reind.mtz %s %s %s %s dimple%s\n" + % (xtal, ref_pdb, ref_mtz, ref_cif, twinRefmac, twin) + + "\n" + "fft hklin dimple%s/final.mtz mapout 2fofc%s.map << EOF\n" % (twin, twin) + + " labin F1=FWT PHI=PHWT\n" + "EOF\n" + "\n" + "fft hklin dimple%s/final.mtz mapout fofc%s.map << EOF\n" % (twin, twin) + + " labin F1=DELFWT PHI=PHDELWT\n" + "EOF\n" + "\n" + "cd %s\n" % os.path.join(self.initial_model_directory, xtal) + "\n" + "/bin/rm dimple%s.pdb\n" % twin + "/bin/rm dimple%s.mtz\n" % twin + "\n" + "ln -s dimple%s/dimple%s/final.pdb dimple%s.pdb\n" % (twin, twin, twin) + + "ln -s dimple%s/dimple%s/final.mtz dimple%s.mtz\n" % (twin, twin, twin) + + "\n" + "/bin/rm init%s.pdb\n" % twin + "/bin/rm init%s.mtz\n" % twin + "\n" + "ln -s dimple%s.pdb init%s.pdb\n" % (twin, twin) + + "ln -s dimple%s.mtz init%s.mtz\n" % (twin, twin) + + "\n" + "/bin/rm 2fofc%s.map\n" % twin + "/bin/rm fofc%s.map\n" % twin + "\n" + "ln -s dimple%s/2fofc%s.map .\n" % (twin, twin) + + "ln -s dimple%s/fofc%s.map .\n" % (twin, twin) + + "\n" + "$CCP4/bin/ccp4-python " + + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "update_data_source_for_new_dimple%s_pdb.py" % twin, + ) + + " {0!s} {1!s} {2!s}\n".format( + os.path.join(self.database_directory, self.data_source_file), + xtal, + self.initial_model_directory, + ) + + "\n" + "/bin/rm dimple_run_in_progress\n" + "\n" + ) + + os.chdir(self.ccp4_scratch_directory) + f = open( + "xce_{0!s}{1!s}_{2!s}.sh".format(self.pipeline, twin, str(self.n)), "w" + ) + f.write(Cmds) + f.close() + os.system( + "chmod +x xce_{0!s}{1!s}_{2!s}.sh".format(self.pipeline, twin, str(self.n)) + ) + self.n += 1 + db_dict = {"DimpleStatus": "started"} + self.Logfile.insert( + "{0!s}: setting DataProcessingStatus flag to started".format(xtal) + ) + self.db.update_data_source(xtal, db_dict) + return twin + + def run_script(self, twin): + # submit job + self.Logfile.insert( + "created input scripts for " + + str(self.n) + + " in " + + self.ccp4_scratch_directory + ) + os.chdir(self.ccp4_scratch_directory) + Cmds = ( + "#!/bin/bash\n" + + ". /etc/profile.d/modules.sh\n" + + "./xce_{!s}{!s}_$SLURM_ARRAY_TASK_ID.sh\n".format(self.pipeline, twin) + ) + f = open("{!s}{!s}_master.sh".format(self.pipeline, twin), "w") + f.write(Cmds) + f.close() + slurm.submit_cluster_job( + "xce_{!s}{!s}_master".format(self.pipeline, twin), + "{!s}{!s}_master.sh".format(self.pipeline, twin), + self.xce_logfile, + self.slurm_token, + array="1-{!s}".format(self.n - 1), + ) + + +class remove_selected_dimple_files(QtCore.QThread): + def __init__( + self, + sample_list, + initial_model_directory, + xce_logfile, + database_directory, + data_source_file, + pipeline, + ): + QtCore.QThread.__init__(self) + self.sample_list = sample_list + self.initial_model_directory = initial_model_directory + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source( + os.path.join(database_directory, data_source_file) + ) + self.pipeline = pipeline + + def run(self): + progress_step = 1 + if len(self.sample_list) != 0: + progress_step = 100 / float(len(self.sample_list)) + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + for n, xtal in enumerate(self.sample_list): + db_dict = {} + if not os.path.isdir(os.path.join(self.initial_model_directory, xtal)): + self.Logfile.insert("{0!s}: directory does not exist".format(xtal)) + continue + os.chdir(os.path.join(self.initial_model_directory, xtal)) + + if self.pipeline == "dimple": + if os.path.isfile("init.pdb"): + if "dimple" in os.path.realpath("init.pdb"): + self.Logfile.warning( + "{0!s}: init.pdb & init.mtz is linked to" + " dimple outcome".format(xtal) + ) + self.Logfile.warning( + "{0!s}: removing init.pdb & init.mtz & (2)fofc maps".format( + xtal + ) + ) + db_dict = self.remove_init(db_dict) + else: + db_dict = self.remove_init(db_dict) + self.Logfile.warning( + "{0!s}: removing dimple folder & dimple.pdb/dimple.mtz".format(xtal) + ) + os.system("/bin/rm dimple_run_in_progress 2> /dev/null") + os.system("/bin/rm dimple.pdb 2> /dev/null") + os.system("/bin/rm dimple.mtz 2> /dev/null") + os.system("/bin/rm -fr dimple") + elif self.pipeline == "pipedream": + if os.path.isfile("init.pdb"): + if "dimple" in os.path.realpath("init.pdb"): + self.Logfile.warning( + "{0!s}: init.pdb & init.mtz is linked to" + " pipedream outcome".format(xtal) + ) + self.Logfile.warning( + "{0!s}: removing init.pdb & init.mtz & (2)fofc maps".format( + xtal + ) + ) + db_dict = self.remove_init(db_dict) + else: + db_dict = self.remove_init(db_dict) + self.Logfile.warning( + "{0!s}: removing pipedream folder &" + " pipedream.pdb/pipedream.mtz".format(xtal) + ) + os.system("/bin/rm pipedream_run_in_progress 2> /dev/null") + os.system("/bin/rm pipedream.pdb 2> /dev/null") + os.system("/bin/rm pipedream.mtz 2> /dev/null") + os.system("/bin/rm -fr pipedream") + elif self.pipeline == "phenix.ligand_pipeline": + if os.path.isfile("init.pdb"): + if "dimple" in os.path.realpath("init.pdb"): + self.Logfile.warning( + "{0!s}: init.pdb & init.mtz is linked to" + " phenix.ligand_pipeline outcome".format(xtal) + ) + self.Logfile.warning( + "{0!s}: removing init.pdb & init.mtz & (2)fofc maps".format( + xtal + ) + ) + db_dict = self.remove_init(db_dict) + else: + db_dict = self.remove_init(db_dict) + self.Logfile.warning( + "{0!s}: removing phenix.ligand_pipeline folder &" + " phenix.ligand_pipeline.pdb/phenix.ligand_pipeline.mtz".format( + xtal + ) + ) + os.system("/bin/rm phenix.ligand_pipeline_run_in_progress 2> /dev/null") + os.system("/bin/rm phenix.ligand_pipeline.pdb 2> /dev/null") + os.system("/bin/rm phenix.ligand_pipeline.mtz 2> /dev/null") + os.system("/bin/rm -fr phenix.ligand_pipeline") + + if db_dict != {}: + self.Logfile.insert("{0!s}: updating database".format(xtal)) + self.db.update_data_source(xtal, db_dict) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + def remove_init(self, db_dict): + os.system("/bin/rm init.pdb") + os.system("/bin/rm init.mtz") + os.system("/bin/rm 2fofc.map") + os.system("/bin/rm fofc.map") + db_dict["DimpleResolutionHigh"] = "" + db_dict["DimpleRcryst"] = "" + db_dict["DimpleRfree"] = "" + db_dict["DimplePathToPDB"] = "" + db_dict["DimplePathToMTZ"] = "" + db_dict["DimpleReferencePDB"] = "" + db_dict["DimplePANDDAwasRun"] = "False" + db_dict["DimplePANDDAhit"] = "False" + db_dict["DimplePANDDAreject"] = "False" + db_dict["DimplePANDDApath"] = "" + db_dict["DimpleStatus"] = "pending" + return db_dict + + +class set_results_from_selected_pipeline(QtCore.QThread): + def __init__( + self, + sample_list, + initial_model_directory, + xce_logfile, + database_directory, + data_source_file, + pipeline, + ): + QtCore.QThread.__init__(self) + self.sample_list = sample_list + self.initial_model_directory = initial_model_directory + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source( + os.path.join(database_directory, data_source_file) + ) + self.pipeline = pipeline + + def run(self): + progress_step = 1 + if len(self.sample_list) != 0: + progress_step = 100 / float(len(self.sample_list)) + progress = 0 + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + for n, xtal in enumerate(self.sample_list): + db_dict = {} + if not os.path.isdir(os.path.join(self.initial_model_directory, xtal)): + self.Logfile.insert("{0!s}: directory does not exist".format(xtal)) + continue + os.chdir(os.path.join(self.initial_model_directory, xtal)) + + if os.path.isfile("init.pdb"): + self.Logfile.warning("{0!s}: init.pdb & init.mtz exist".format(xtal)) + self.Logfile.warning( + "{0!s}: removing init.pdb & init.mtz & (2)fofc maps".format(xtal) + ) + os.system("/bin/rm init.pdb") + os.system("/bin/rm init.mtz") + os.system("/bin/rm 2fofc.map") + os.system("/bin/rm fofc.map") + db_dict["DimpleResolutionHigh"] = "" + db_dict["DimpleRcryst"] = "" + db_dict["DimpleRfree"] = "" + db_dict["DimplePathToPDB"] = "" + db_dict["DimplePathToMTZ"] = "" + db_dict["DimpleReferencePDB"] = "" + db_dict["DimplePANDDAwasRun"] = "False" + db_dict["DimplePANDDAhit"] = "False" + db_dict["DimplePANDDAreject"] = "False" + db_dict["DimplePANDDApath"] = "" + db_dict["DimpleStatus"] = "pending" + + if self.pipeline == "dimple": + if os.path.isfile("dimple.pdb"): + self.Logfile.insert("%s: selecting output from dimple" % xtal) + os.system("ln -s dimple.pdb init.pdb") + pdb_info = XChemUtils.parse().PDBheader("dimple.pdb") + db_dict["DimpleRcryst"] = pdb_info["Rcryst"] + db_dict["DimpleRfree"] = pdb_info["Rfree"] + db_dict["DimpleResolutionHigh"] = pdb_info["ResolutionHigh"] + db_dict["DimpleStatus"] = "finished" + db_dict["DimplePathToPDB"] = os.path.realpath("dimple.pdb") + if os.path.isfile("dimple.mtz"): + os.system("ln -s dimple.mtz init.mtz") + db_dict["DimplePathToMTZ"] = os.path.realpath("dimple.mtz") + if os.path.isfile("dimple/2fofc.map"): + os.system("ln -s dimple/2fofc.map .") + if os.path.isfile("dimple/fofc.map"): + os.system("ln -s dimple/fofc.map .") + elif self.pipeline == "pipedream": + if os.path.isfile("pipedream.pdb"): + self.Logfile.insert("%s: selecting output from pipedream" % xtal) + os.system("ln -s pipedream.pdb init.pdb") + pdb_info = XChemUtils.parse().PDBheader("pipedream.pdb") + db_dict["DimpleRcryst"] = pdb_info["Rcryst"] + db_dict["DimpleRfree"] = pdb_info["Rfree"] + db_dict["DimpleResolutionHigh"] = pdb_info["ResolutionHigh"] + db_dict["DimpleStatus"] = "finished" + db_dict["DimplePathToPDB"] = os.path.realpath("pipedream.pdb") + if os.path.isfile("pipedream.mtz"): + os.system("ln -s pipedream.mtz init.mtz") + db_dict["DimplePathToMTZ"] = os.path.realpath("pipedream.mtz") + if os.path.isfile("pipedream/2fofc.map"): + os.system("ln -s pipedream/2fofc.map .") + if os.path.isfile("pipedream/fofc.map"): + os.system("ln -s pipedream/fofc.map .") + elif self.pipeline == "phenix.ligand_pipeline": + if os.path.isfile("phenix.ligand_pipeline.pdb"): + self.Logfile.insert( + "%s: selecting output from phenix.ligand_pipeline" % xtal + ) + os.system("ln -s phenix.ligand_pipeline.pdb init.pdb") + pdb_info = XChemUtils.parse().PDBheader( + "phenix.ligand_pipeline.pdb" + ) + db_dict["DimpleRcryst"] = pdb_info["Rcryst"] + db_dict["DimpleRfree"] = pdb_info["Rfree"] + db_dict["DimpleResolutionHigh"] = pdb_info["ResolutionHigh"] + db_dict["DimpleStatus"] = "finished" + db_dict["DimplePathToPDB"] = os.path.realpath( + "phenix.ligand_pipeline.pdb" + ) + if os.path.isfile("phenix.ligand_pipeline.mtz"): + os.system("ln -s phenix.ligand_pipeline.mtz init.mtz") + db_dict["DimplePathToMTZ"] = os.path.realpath( + "phenix.ligand_pipeline.mtz" + ) + if os.path.isfile("phenix.ligand_pipeline/2fofc.map"): + os.system("ln -s phenix.ligand_pipeline/2fofc.map .") + if os.path.isfile("phenix.ligand_pipeline/fofc.map"): + os.system("ln -s phenix.ligand_pipeline/fofc.map .") + + self.Logfile.insert("{0!s}: updating database".format(xtal)) + self.db.update_data_source(xtal, db_dict) + + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.emit(QtCore.SIGNAL("datasource_menu_reload_samples")) + + +class start_COOT(QtCore.QThread): + def __init__(self, settings, interface): + QtCore.QThread.__init__(self) + self.settings = settings + if interface == "test": + self.pylib = "XChemCoot.py" + elif interface == "new": + self.pylib = "XChemCootNew.py" + elif interface == "panddaV1": + self.pylib = "XChemCootOld.py" + elif interface == "reference": + self.pylib = "XChemCootReference.py" + elif interface == "buster": + self.pylib = "XChemCootBuster.py" + elif interface == "dimple_twin": + self.pylib = "XChemCootTwin.py" + + def run(self): + # coot at Diamond always or sometimes at least open in home directory + # so then it won't find the .pkl file + pickle.dump( + self.settings, + open(os.path.join(os.getenv("HOME"), ".xce_settings.pkl"), "wb"), + ) + os.system( + "cd {0!s}\ncoot --no-guano --no-state-script --script {1!s}".format( + os.getenv("HOME"), + os.path.join(os.getenv("XChemExplorer_DIR"), "coot", self.pylib), + ) + ) + + +class start_pandda_inspect(QtCore.QThread): + def __init__(self, settings, xce_logfile): + QtCore.QThread.__init__(self) + self.panddas_directory = settings["panddas_directory"] + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + + def run(self): + Cmds = ( + "#!" + os.getenv("SHELL") + "\n" + "unset PYTHONPATH\n" + "module load buster/20240123\n" + "source /dls/science/groups/i04-1/software/pandda_0.2.12" + "/ccp4/ccp4-7.0/bin/ccp4.setup-sh\n" + "cd " + self.panddas_directory + "\n" + "pandda.inspect\n" + ) + + self.Logfile.insert( + "starting pandda.inspect with the following command:\n" + Cmds + ) + os.system(Cmds) + + +# --- new module from hell ------------------------------------------------------------- + + +class read_pinIDs_from_gda_logs(QtCore.QThread): + def __init__(self, beamline, visit, database, gdaLogInstructions, xce_logfile): + QtCore.QThread.__init__(self) + self.beamline = beamline + self.visit = visit + + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + + self.db = XChemDB.data_source(database) + self.allSamples = self.db.collected_xtals_during_visit_for_scoring(visit) + + self.gdaLogInstructions = gdaLogInstructions + self.gda_log_start_line = gdaLogInstructions[0] + self.gzipped_logs_parsed = gdaLogInstructions[1] + + def run(self): + if self.gzipped_logs_parsed: + self.Logfile.insert("parsed gzipped gda logfiles before, won't do again...") + self.Logfile.insert( + "will start parsing of current gda logfile at line {0!s}".format( + str(self.gda_log_start_line) + ) + ) + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "checking GDA logiles for pinID details", + ) + pinDict, self.gda_log_start_line = XChemMain.get_gda_barcodes( + self.allSamples, + self.gzipped_logs_parsed, + self.gda_log_start_line, + self.beamline, + self.xce_logfile, + ) + + self.update_database(pinDict) + + self.gdaLogInstructions = [self.gda_log_start_line, True] + self.Logfile.insert("====== finished checking GDA logfiles ======") + self.emit( + QtCore.SIGNAL("update_gdaLog_parsing_instructions_and_score"), + self.gdaLogInstructions, + ) + self.emit(QtCore.SIGNAL("finished()")) + + def update_database(self, pinDict): + self.Logfile.insert("updating database with pinDIs from GDA logfiles") + + progress = 0 + progress_step = XChemMain.getProgressSteps(len(pinDict)) + + for sample in pinDict: + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "updating pinID in DB for " + sample, + ) + dbDict = {} + dbDict["DataCollectionPinBarcode"] = pinDict[sample] + self.db.update_specified_table(sample, dbDict, "collectionTable") + progress += progress_step + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + +class choose_autoprocessing_outcome(QtCore.QThread): + def __init__( + self, + database, + visit, + reference_file_list, + preferences, + projectDir, + rescore, + xce_logfile, + agamemnon, + ): + QtCore.QThread.__init__(self) + self.visit = visit + self.projectDir = projectDir + self.reference_file_list = reference_file_list + self.rescore = rescore + self.selection_mechanism = preferences["dataset_selection_mechanism"] + self.acceptable_unitcell_volume_difference = preferences[ + "allowed_unitcell_difference_percent" + ] + self.acceptable_low_resolution_limit_for_data = preferences[ + "acceptable_low_resolution_limit_for_data" + ] + self.acceptable_low_resolution_Rmerge = preferences[ + "acceptable_low_resolution_Rmerge" + ] + self.agamemnon = agamemnon + self.xce_logfile = xce_logfile + self.Logfile = XChemLog.updateLog(xce_logfile) + + self.db = XChemDB.data_source(os.path.join(database)) + if self.agamemnon: + self.allSamples = [] + for v in self.visit: + x = self.db.collected_xtals_during_visit_for_scoring(v) + for e in x: + self.allSamples.append(e) + else: + self.allSamples = self.db.collected_xtals_during_visit_for_scoring(visit) + + def run(self): + progress = 0 + progress_step = XChemMain.getProgressSteps(len(self.allSamples)) + + for sample in sorted(self.allSamples): + if self.db.autoprocessing_result_user_assigned(sample) and not self.rescore: + if os.path.isfile( + os.path.join(self.projectDir, sample, sample + ".mtz") + ): + self.Logfile.warning( + "{0!s}: user has manually selected auto-processing result;" + " will NOT auto-select!".format(sample) + ) + continue + else: + self.Logfile.warning( + "{0!s}: user has manually selected auto-processing result" + " before, but {1!s}.mtz does not exist".format(sample, sample) + ) + self.Logfile.insert("%s: selecting autoprocessing result" % sample) + elif self.rescore: + self.Logfile.warning( + "{0!s}: rescore selected -> might overwrite user selection!".format( + sample + ) + ) + else: + self.Logfile.insert("%s: selecting autoprocessing result" % sample) + dbList = self.db.all_autoprocessing_results_for_xtal_as_dict(sample) + self.Logfile.insert( + "%s: found %s different autoprocessing results" + % (sample, str(len(dbList))) + ) + + # 0.) first check for which results files actually exist + # + dbList = self.checkExistingFiles(dbList, sample) + if not dbList: + self.Logfile.error( + sample + ": cannot find any MTZ & LOG files; skipping..." + ) + continue + + # 1.) if posssible, only carry forward samples with similar UCvolume + # and same point group + dbList = self.selectResultsSimilarToReference(dbList) + + # 2.) if possible, only carry forward samples with low resolution Rmerge + # smaller than specified in perferences + dbList = self.selectResultsWithAcceptableLowResoRmerge(dbList) + + # 3.) Make selection based on speified selection mechanism + if self.selection_mechanism == "IsigI*Comp*UniqueRefl": + dbDict = self.selectHighestScore(dbList) + elif self.selection_mechanism == "highest_resolution": + dbDict = self.selectHighestResolution(dbList) + elif "only" in self.selection_mechanism: + dbDict = self.selectSpecificPipelineOnly(dbList) + + # 4.) Set new symbolic links in project directory + XChemMain.linkAutoProcessingResult( + sample, dbDict, self.projectDir, self.xce_logfile + ) + + # 5.) Determine DataProcessing Outcome + dbDict["DataCollectionOutcome"] = self.determine_processing_outcome(dbDict) + + # 6.) update database + dbDict["DataProcessingAutoAssigned"] = "True" + self.updateDB(sample, dbDict) + + progress += progress_step + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "scoring auto-processing results for " + sample, + ) + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.Logfile.insert("====== finished scoring data processing results ======") + self.emit(QtCore.SIGNAL("populate_datasets_summary_table_NEW")) + self.emit(QtCore.SIGNAL("finished()")) + + def report_forward_carried_pipelines(self, dbListOut, dbList): + if not dbListOut: + dbListOut = dbList + self.Logfile.warning( + "none of the MTZ files fulfilled criteria;" + " will carry forward all results:" + ) + else: + self.Logfile.insert( + "will carry forward the MTZ files from the following auto-processing" + " pipelines:" + ) + self.Logfile.insert( + "{0:30} {1:10} {2:10} {3:10}".format( + "pipeline", "Rmerge(Low)", "PG", "Score" + ) + ) + self.Logfile.insert( + "----------------------------------------------------------------------" + ) + for resultDict in dbListOut: + self.Logfile.insert( + "{0:30} {1:10} {2:10} {3:10}".format( + resultDict["DataProcessingProgram"], + resultDict["DataProcessingRmergeLow"], + resultDict["DataProcessingPointGroup"], + resultDict["DataProcessingScore"], + ) + ) + return dbListOut + + def checkExistingFiles(self, dbList, xtal): + self.Logfile.insert("checking if MTZ & LOG files exisit") + os.chdir(os.path.join(self.projectDir, xtal)) + self.Logfile.insert( + xtal + ": changing directory " + os.path.join(self.projectDir, xtal) + ) + dbListOut = [] + for resultDict in dbList: + try: + run = resultDict["DataCollectionRun"] + subDir = resultDict["DataCollectionSubdir"] + if subDir != "": + procCode = "_" + subDir + else: + procCode = "" + visit = resultDict["DataCollectionVisit"] + autoproc = resultDict["DataProcessingProgram"] + mtzFileAbs = resultDict["DataProcessingPathToMTZfile"] + mtzfileName = mtzFileAbs[mtzFileAbs.rfind("/") + 1 :] + logFileAbs = resultDict["DataProcessingPathToLogfile"] + logfileName = logFileAbs[logFileAbs.rfind("/") + 1 :] + + mtzfile = os.path.join( + "autoprocessing", + visit + "-" + run + autoproc + procCode, + mtzfileName, + ) + logfile = os.path.join( + "autoprocessing", + visit + "-" + run + autoproc + procCode, + logfileName, + ) + + if os.path.isfile(mtzfile): + self.Logfile.insert(xtal + ": found " + mtzfile) + if os.path.isfile(logfile): + self.Logfile.insert(xtal + ": found " + logfile) + dbListOut.append(resultDict) + else: + self.Logfile.error( + xtal + ": cannot find " + logfile + " ; skipping..." + ) + else: + self.Logfile.error( + xtal + ": cannot find " + mtzfile + " ; skipping..." + ) + + except ValueError: + pass + return dbListOut + + def selectResultsSimilarToReference(self, dbList): + self.Logfile.insert( + "checking if MTZ files are similar to supplied reference files" + ) + dbListOut = [] + for resultDict in dbList: + try: + if isinstance(float(resultDict["DataProcessingUnitCellVolume"]), float): + self.Logfile.insert( + "checking unit cell volume difference and point group:" + ) + for reference_file in self.reference_file_list: + if not reference_file[4] == 0: + self.Logfile.insert( + "unitcell volume reference:" + str(reference_file[4]) + ) + self.Logfile.insert( + "unitcell volume dataset: " + + str(resultDict["DataProcessingUnitCellVolume"]) + ) + unitcell_difference = round( + ( + math.fabs( + reference_file[4] + - float( + resultDict["DataProcessingUnitCellVolume"] + ) + ) + / reference_file[4] + ) + * 100, + 1, + ) + self.Logfile.insert( + resultDict["DataProcessingProgram"] + + ": " + + str(unitcell_difference) + + "% difference -> pg(ref): " + + reference_file[5] + + " -> pg(mtz): " + + resultDict["DataProcessingPointGroup"] + ) + if ( + unitcell_difference + < self.acceptable_unitcell_volume_difference + and reference_file[5] + == resultDict["DataProcessingPointGroup"] + ): + self.Logfile.insert( + "=> passed -> mtz file has same point group" + " as reference file and similar unit cell volume" + ) + dbListOut.append(resultDict) + else: + self.Logfile.warning( + "mtz file has different point group/" + " unit cell volume as reference file" + ) + except ValueError: + pass + dbListOut = self.report_forward_carried_pipelines(dbListOut, dbList) + return dbListOut + + def selectResultsWithAcceptableLowResoRmerge(self, dbList): + self.Logfile.insert( + "checking if MTZ files have acceptable low resolution Rmerge values" + " (currently set to %s)" % str(self.acceptable_low_resolution_Rmerge) + ) + dbListOut = [] + for resultDict in dbList: + try: + if ( + float(resultDict["DataProcessingRmergeLow"]) + < self.acceptable_low_resolution_Rmerge + ): + self.Logfile.insert( + resultDict["DataProcessingProgram"] + + ": Rmerge(low) of MTZ file is below threshold: " + + str(resultDict["DataProcessingRmergeLow"]) + ) + dbListOut.append(resultDict) + else: + self.Logfile.warning( + resultDict["DataProcessingProgram"] + + ": Rmerge(low) of MTZ file is ABOVE threshold: " + + str(resultDict["DataProcessingRmergeLow"]) + ) + except ValueError: + pass + dbListOut = self.report_forward_carried_pipelines(dbListOut, dbList) + return dbListOut + + def selectHighestScore(self, dbList): + tmp = [] + for resultDict in dbList: + try: + tmp.append(float(resultDict["DataProcessingScore"])) + except ValueError: + tmp.append(0.0) + highestScoreDict = dbList[tmp.index(max(tmp))] + return highestScoreDict + + def selectHighestResolution(self, dbList): + tmp = [] + for resultDict in dbList: + try: + tmp.append(float(resultDict["DataProcessingResolutionHigh"])) + except ValueError: + tmp.append(100.0) + highestResoDict = dbList[tmp.index(min(tmp))] + return highestResoDict + + def selectSpecificPipelineOnly(self, dbList): + tmp = [] + self.Logfile.insert( + "selecting datasets by auto-processing pipeline: " + + self.selection_mechanism + ) + for resultDict in dbList: + if ( + self.selection_mechanism == "dials - only" + and "dials" in resultDict["DataProcessingProgram"] + ): + tmp.append(resultDict) + if ( + self.selection_mechanism == "xia2 3d - only" + and "3d-" in resultDict["DataProcessingProgram"] + ): + tmp.append(resultDict) + if ( + self.selection_mechanism == "xia2 3dii - only" + and "3dii" in resultDict["DataProcessingProgram"] + ): + tmp.append(resultDict) + if ( + self.selection_mechanism == "autoProc - only" + and "autoPROC" in resultDict["DataProcessingProgram"] + and "staraniso" not in resultDict["DataProcessingProgram"] + ): + tmp.append(resultDict) + if ( + self.selection_mechanism == "autoProc_staraniso - only" + and "autoPROC" in resultDict["DataProcessingProgram"] + and "staraniso" in resultDict["DataProcessingProgram"] + ): + tmp.append(resultDict) + if not tmp: + tmp = dbList + pipelineDict = self.selectHighestScore(tmp) + return pipelineDict + + def determine_processing_outcome(self, db_dict): + outcome = "Failed - unknown" + try: + if ( + float(db_dict["DataProcessingResolutionHigh"]) + < self.acceptable_low_resolution_limit_for_data + ): + outcome = "success" + else: + outcome = "Failed - low resolution" + except ValueError: + pass + return outcome + + def updateDB(self, sample, dbDict): + self.Logfile.insert("{0!s}: updating database".format(sample)) + self.db.update_insert_data_source(sample, dbDict) + + +class read_write_autoprocessing_results_from_to_disc(QtCore.QThread): + """ + major changes: + - pkl file is obsolete + - results for every autoprocessing result is recorded in new DB table + - crystal centring images are copied into project directory + - beamline directory in project directory will not be used anymore + - users need to actively select the actual data collection visit as Data Collection + Directory in the settings tab (e.g. /dls/i04-1/data/2017/mx15433-50 + - results from fast_dp are not copied over and included in analysis + + - DB mainTable gets flag if user updated autoprocessing selection + - checking of reprocessed files needs to be explicit + - all dictionaries used to store information are retired + - at the moment one can only review/ rescore crystals collected during the selected + visit + - parsing of pinIDs in gda logfiles is still missing + """ + + def __init__( + self, processedDir, database, projectDir, xce_logfile, target, agamemnon + ): + QtCore.QThread.__init__(self) + self.processedDir = processedDir + self.visit, self.beamline = XChemMain.getVisitAndBeamline(self.processedDir) + self.projectDir = projectDir + self.Logfile = XChemLog.updateLog(xce_logfile) + self.target = target + self.agamemnon = agamemnon + + self.db = XChemDB.data_source(os.path.join(database)) + self.exisitingSamples = self.getExistingSamples() + + self.toParse = [ + [ + os.path.join("*"), + os.path.join("LogFiles", "*aimless.log"), + os.path.join("DataFiles", "*free.mtz"), + ], + [ + os.path.join("*"), + os.path.join("LogFiles", "*merging-statistics.json"), + os.path.join("DataFiles", "*free.mtz"), + ], + [ + os.path.join("multi-xia2", "*"), + os.path.join("LogFiles", "*aimless.log"), + os.path.join("DataFiles", "*free.mtz"), + ], + [os.path.join("autoPROC"), "*aimless.log", "*truncate-unique.mtz"], + [ + os.path.join("autoPROC"), + # staraniso_alldata-unique.table1 only available in tar archive + "*summary.tar.gz", + "*staraniso_alldata-unique.mtz", + ], + [os.path.join("autoPROC-*"), "*aimless.log", "*truncate-unique.mtz"], + [ + os.path.join("autoPROC-*"), + "*summary.tar.gz", + "*staraniso_alldata-unique.mtz", + ], + ] + + def run(self): + self.parse_file_system() + + def getExistingSamples(self): + existingSamples = {} + self.Logfile.insert("reading existing samples from collectionTable") + allEntries = self.db.execute_statement( + "select CrystalName,DataCollectionVisit,DataCollectionRun," + "DataProcessingProgram, DataCollectionSubdir from collectionTable where" + ' DataCollectionOutcome = "success"' + ) + for item in allEntries: + if str(item[0]) not in existingSamples: + existingSamples[str(item[0])] = [] + self.Logfile.insert("%s: adding %s" % (str(item[0]), str(item[1]))) + # visit-runautoproc-subdir + existingSamples[str(item[0])].append( + str(item[1]) + "-" + str(item[2]) + str(item[3]) + "-" + str(item[4]) + ) + return existingSamples + + def createSampleDir(self, xtal): + if not os.path.isdir(os.path.join(self.projectDir, xtal)): + os.mkdir(os.path.join(self.projectDir, xtal)) + + def createAutoprocessingDir(self, xtal, run, autoproc, proc_code): + # create all the directories if necessary + self.Logfile.insert( + "%s: checking if new directory needs to be created for %s" + % ( + xtal, + os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + ), + ) + ) + if not os.path.isdir(os.path.join(self.projectDir, xtal, "autoprocessing")): + os.mkdir(os.path.join(self.projectDir, xtal, "autoprocessing")) + if not os.path.isdir( + os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + ) + ): + self.Logfile.insert( + "%s: making directory %s" + % ( + xtal, + os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + ), + ) + ) + os.mkdir( + os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + ) + ) + else: + self.Logfile.warning("%s: directory exists; skipping..." % xtal) + + def cleanUpDir(self, xtal, run, autoproc, mtzfile, logfile, proc_code): + toKeep = [ + "staraniso_alldata-unique.mtz", + "staraniso_alldata-unique.table1", + "staraniso_alldata.log", + xtal + ".mtz", + xtal + ".log", + ] + os.chdir( + os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + ) + ) + for files in glob.glob("*"): + if files not in toKeep: + os.system("/bin/rm -f " + files) + + def copyMTZandLOGfiles(self, xtal, run, autoproc, mtzfile, logfile, proc_code): + mtzNew = "" + logNew = "" + os.chdir( + os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + ) + ) + # MTZ file + if not os.path.isfile(mtzfile[mtzfile.rfind("/") + 1 :]): + self.Logfile.insert("%s: copying %s" % (xtal, mtzfile)) + os.system("/bin/cp " + mtzfile + " .") + for mmcif in glob.glob(os.path.join(mtzfile[: mtzfile.rfind("/")], "*")): + if mmcif.endswith(".mmcif"): + self.Logfile.insert("%s: copying %s" % (xtal, mmcif)) + os.system("/bin/cp " + mmcif + " .") + elif mmcif.endswith(".mmcif.bz2"): + self.Logfile.insert( + "%s: copying and decompressing %s" % (xtal, mmcif) + ) + os.system("/bin/cp " + mmcif + " .") + os.system("bzip2 -d ./" + mmcif) + if os.path.isfile(mtzfile[mtzfile.rfind("/") + 1 :]) and not os.path.isfile( + xtal + ".mtz" + ): + os.symlink(mtzfile[mtzfile.rfind("/") + 1 :], xtal + ".mtz") + if os.path.isfile(mtzfile[mtzfile.rfind("/") + 1 :]): + mtzNew = os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + mtzfile[mtzfile.rfind("/") + 1 :], + ) + # MTZ file unmerged + if os.path.isfile(mtzfile.replace("_free.mtz", "_scaled_unmerged.mtz")): + self.Logfile.insert("%s: found unmerged mtz file" % xtal) + if not os.path.isfile(xtal + "_unmerged.mtz"): + self.Logfile.insert( + "%s: copying %s" + % (xtal, mtzfile.replace("_free.mtz", "_scaled_unmerged.mtz")) + ) + os.system( + "/bin/cp " + + mtzfile.replace("_free.mtz", "_scaled_unmerged.mtz") + + " ." + ) + # AIMLESS logfile + if not os.path.isfile(logfile[logfile.rfind("/") + 1 :]): + self.Logfile.insert("%s: copying %s" % (xtal, logfile)) + os.system("/bin/cp " + logfile + " .") + if logfile.endswith("summary.tar.gz"): + self.Logfile.insert("unpacking summary.tar.gz") + os.system("tar -xzvf summary.tar.gz") + logfile = logfile.replace( + "summary.tar.gz", "staraniso_alldata-unique.table1" + ) + self.cleanUpDir(xtal, run, autoproc, mtzfile, logfile, proc_code) + if os.path.isfile(logfile[logfile.rfind("/") + 1 :]) and not os.path.isfile( + xtal + ".log" + ): + os.symlink(logfile[logfile.rfind("/") + 1 :], xtal + ".log") + if os.path.isfile(logfile[logfile.rfind("/") + 1 :]): + logNew = os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + logfile[logfile.rfind("/") + 1 :], + ) + # September 2021: xia2 does not also output a xia2.mmcif and json merging + # statistics file, even if aimless was used for scaling, however, + # the xia2.mmcif file is differently formatted than the one from dials + # hence, if xtal.log file already exists, use this one + if "aimless" in os.readlink(xtal + ".log"): + logNew = os.path.join( + self.projectDir, + xtal, + "autoprocessing", + self.visit + "-" + run + autoproc + "_" + proc_code, + xtal + ".log", + ) + return mtzNew, logNew + + def makeJPGdir(self, xtal, run): + if not os.path.isdir(os.path.join(self.projectDir, xtal, "jpg")): + self.Logfile.insert("making jpg directory in " + xtal) + os.mkdir(os.path.join(self.projectDir, xtal, "jpg")) + if not os.path.isdir( + os.path.join(self.projectDir, xtal, "jpg", self.visit + "-" + run) + ): + os.mkdir(os.path.join(self.projectDir, xtal, "jpg", self.visit + "-" + run)) + + def copyJPGs(self, xtal, run, auto): + self.Logfile.insert("%s: trying to copy crystal snapshots..." % xtal) + found = False + if self.agamemnon: + proposal = self.visit.split("-")[0] + self.Logfile.insert( + "looking for images in " + + os.path.join( + self.processedDir.replace(proposal, self.visit), + "jpegs", + auto, + self.target, + xtal, + run + "*.0.png", + ) + ) + for img in glob.glob( + os.path.join( + self.processedDir.replace(proposal, self.visit), + "jpegs", + auto, + self.target, + xtal, + run + "*.0.png", + ) + ): + if not os.path.isfile( + os.path.join( + self.projectDir, + xtal, + "jpg", + self.visit + "-" + run, + img[img.rfind("/") + 1 :], + ) + ): + self.Logfile.insert("%s: copying %s" % (xtal, img)) + os.system( + "/bin/cp %s %s" + % ( + img, + os.path.join( + self.projectDir, + xtal, + "jpg", + self.visit + "-" + auto + "_" + run, + ), + ) + ) + else: + for img in glob.glob( + os.path.join( + self.processedDir.replace("processed", "jpegs"), run + "*.0.png" + ) + ): + found = True + if not os.path.isfile( + os.path.join( + self.projectDir, + xtal, + "jpg", + self.visit + "-" + run, + img[img.rfind("/") + 1 :], + ) + ): + self.Logfile.insert("%s: copying %s" % (xtal, img)) + os.system( + "/bin/cp %s %s" + % ( + img, + os.path.join( + self.projectDir, xtal, "jpg", self.visit + "-" + run + ), + ) + ) + if not found: + for img in glob.glob( + os.path.join( + self.processedDir.replace("processed", "jpegs"), + xtal, + run + "*.0.png", + ) + ): + if not os.path.isfile( + os.path.join( + self.projectDir, + xtal, + "jpg", + self.visit + "-" + run, + img[img.rfind("/") + 1 :], + ) + ): + self.Logfile.insert("%s: copying %s" % (xtal, img)) + os.system( + "/bin/cp %s %s" + % ( + img, + os.path.join( + self.projectDir, xtal, "jpg", self.visit + "-" + run + ), + ) + ) + + def findJPGs(self, xtal, run): + jpgDict = {} + for n, img in enumerate( + glob.glob( + os.path.join( + self.projectDir, xtal, "jpg", self.visit + "-" + run, "*.0.png" + ) + ) + ): + if n <= 3: + jpgDict["DataCollectionCrystalImage" + str(n + 1)] = img + return jpgDict + + def readProcessingUpdateResults( + self, xtal, folder, log, mtz, timestamp, current_run, autoproc, proc_code + ): + db_dict = {} + self.Logfile.warning("%s: looking for %s" % (xtal, os.path.join(folder, mtz))) + for mtzfile in glob.glob(os.path.join(folder, mtz)): + self.Logfile.insert("%s: found %s" % (xtal, mtzfile)) + self.Logfile.warning( + "%s: looking for %s" % (xtal, os.path.join(folder, log)) + ) + for logfile in glob.glob(os.path.join(folder, log)): + self.Logfile.insert("%s: found %s" % (xtal, logfile)) + self.createAutoprocessingDir(xtal, current_run, autoproc, proc_code) + mtzNew, logNew = self.copyMTZandLOGfiles( + xtal, current_run, autoproc, mtzfile, logfile, proc_code + ) + if self.target == "=== project directory ===": + target = "unknown" + else: + target = self.target + db_dict = { + "DataCollectionDate": timestamp, + "DataProcessingPathToLogfile": logNew, + "DataProcessingPathToMTZfile": mtzNew, + "DataProcessingDirectoryOriginal": folder, + # success in collection Table only means that a logfile was found + "DataCollectionOutcome": "success", + "ProteinName": target, + } + db_dict.update(XChemUtils.parse().read_aimless_logfile(logNew)) + # image exist even if data processing failed + db_dict.update(self.findJPGs(xtal, current_run)) + db_dict["DataCollectionBeamline"] = self.beamline + self.update_data_collection_table( + xtal, current_run, autoproc, db_dict, proc_code + ) + + def getAutoProc(self, folder_rel, staraniso): + self.Logfile.insert("checking name of auto-processing pipeline...") + folder = os.path.realpath(folder_rel) + self.Logfile.insert("folder: " + folder) + autoproc = "unknown" + if "ap-run" in folder: + autoproc = "autoPROC" + else: + for f in folder.split("/"): + if "autoPROC" in f: + autoproc = f + staraniso + break + elif "xia2" in f: + autoproc = f + break + elif "dials" in f: + autoproc = f + break + self.Logfile.insert("name of auto-processing pipeline: %s" % autoproc) + return autoproc + + def update_data_collection_table( + self, xtal, current_run, autoproc, db_dict, proc_code + ): + condition_dict = { + "CrystalName": xtal, + "DataCollectionVisit": self.visit, + "DataCollectionRun": current_run, + "DataCollectionSubdir": proc_code, + "DataProcessingProgram": autoproc, + } + self.db.update_insert_any_table("collectionTable", db_dict, condition_dict) + + def alreadyParsed(self, xtal, current_run, proc_code, autoproc): + parsed = False + self.Logfile.insert("checking if this processed directory was already parsed") + if xtal in self.exisitingSamples: + self.Logfile.insert(xtal + " exists in collectionTable") + self.Logfile.insert("current identifier:") + self.Logfile.insert( + self.visit + "-" + current_run + autoproc + "-" + proc_code + ) + self.Logfile.insert("indentifier in collectionTable") + for x in self.exisitingSamples[xtal]: + self.Logfile.insert(x) + # visit-runautoproc-subdir + if ( + self.visit + "-" + current_run + autoproc + "-" + proc_code + in self.exisitingSamples[xtal] + ): + self.Logfile.warning( + "%s: results from %s already parsed; skipping..." + % (xtal, self.visit + "-" + current_run + autoproc) + ) + parsed = True + return parsed + + def empty_folder(self, xtal, folder): + empty = True + stuff = [] + for x in glob.glob(os.path.join(folder, "*")): + stuff.append(x) + if not stuff: + self.Logfile.warning( + "{0!s}: {1!s} is empty; probably waiting for autoprocessing to finish;" + " try later!".format(xtal, folder) + ) + else: + empty = False + return empty + + def junk(self, folder): + do_not_parse = False + if not os.path.isdir(folder): + do_not_parse = True + elif "dimple" in folder: + do_not_parse = True + return do_not_parse + + def parse_file_system(self): + if self.agamemnon: + d = self.processedDir[: self.processedDir.rfind("/")] + t = self.processedDir[self.processedDir.rfind("/") + 1 :] + autoDir = os.path.join(d, "auto", t) + else: + autoDir = self.processedDir + + self.Logfile.insert("checking for new data processing results in " + autoDir) + progress = 0 + progress_step = XChemMain.getProgressSteps( + len(glob.glob(os.path.join(autoDir, "*"))) + ) + + runList = [] + self.Logfile.insert("--> " + os.path.join(autoDir, "*")) + for nx, collected_xtals in enumerate( + sorted(glob.glob(os.path.join(autoDir, "*"))) + ): + self.Logfile.insert("%s: %s" % (nx, collected_xtals)) + self.visit = collected_xtals.split("/")[5] + if ( + "tmp" in collected_xtals + or "results" in collected_xtals + or "scre" in collected_xtals + ): + continue + if not os.path.isdir(collected_xtals): + continue + + if ( + "tmp" in collected_xtals + or "results" in collected_xtals + or "scre" in collected_xtals + ): + continue + if not os.path.isdir(collected_xtals): + self.Logfile.warning(collected_xtals + " is not a directory") + continue + + xtal = collected_xtals[collected_xtals.rfind("/") + 1 :] + + self.Logfile.insert("%s: checking auto-processing results" % xtal) + self.createSampleDir(xtal) + + if self.target == "=== project directory ===": + runDir = os.path.join(collected_xtals, "processed", "*") + else: + runDir = os.path.join(collected_xtals, "*") + self.Logfile.insert("current runDir: " + runDir) + + for run in sorted(glob.glob(runDir)): + current_run = run[run.rfind("/") + 1 :] + for code in glob.glob(os.path.join(run, "*")): + if os.path.islink(code): + continue + proc_code = code.split("/")[len(code.split("/")) - 1] + self.Logfile.insert(xtal + ": processed directory -> " + proc_code) + if current_run + proc_code in runList: + continue + self.Logfile.insert( + "%s -> run: %s -> current run: %s -> %s" + % (xtal, run, current_run, proc_code) + ) + timestamp = datetime.fromtimestamp(os.path.getmtime(run)).strftime( + "%Y-%m-%d %H:%M:%S" + ) + # create directory for crystal aligment images in projectDir + self.makeJPGdir(xtal, current_run) + # 'non-auto' is irrelevant here + self.copyJPGs(xtal, current_run, "non-auto") + + for item in self.toParse: + procDir = os.path.join(code, item[0]) + logfile = item[1] + mtzfile = item[2] + self.Logfile.insert( + "%s: search template: procDir - logfile - mtzfile" % xtal + ) + self.Logfile.insert("%s: procDir = %s" % (xtal, procDir)) + self.Logfile.insert("%s: logfile = %s" % (xtal, logfile)) + self.Logfile.insert("%s: mtzfile = %s" % (xtal, mtzfile)) + + for folder in glob.glob(procDir): + staraniso = "" + self.Logfile.insert("%s: searching %s" % (xtal, folder)) + if self.junk(folder): + continue + if self.empty_folder(xtal, folder): + continue + if "staraniso" in logfile or "summary.tar.gz" in logfile: + staraniso = "_staraniso" + autoproc = self.getAutoProc(folder, staraniso) + if self.alreadyParsed( + xtal, current_run, proc_code, autoproc + ): + continue + self.readProcessingUpdateResults( + xtal, + folder, + logfile, + mtzfile, + timestamp, + current_run, + autoproc, + proc_code, + ) + runList.append(current_run + proc_code) + progress += progress_step + self.emit( + QtCore.SIGNAL("update_status_bar(QString)"), + "parsing auto-processing results for " + xtal, + ) + self.emit(QtCore.SIGNAL("update_progress_bar"), progress) + + self.Logfile.insert("====== finished parsing beamline directory ======") + self.emit(QtCore.SIGNAL("read_pinIDs_from_gda_logs")) + self.emit(QtCore.SIGNAL("finished()")) diff --git a/xce/lib/XChemToolTips.py b/xce/lib/XChemToolTips.py new file mode 100755 index 00000000..49172fdd --- /dev/null +++ b/xce/lib/XChemToolTips.py @@ -0,0 +1,365 @@ +import getpass +import os + + +def dataset_task_tip(): + tip = "describes what you can do" + return tip + + +def dataset_task_run_button_tip(): + tip = "Run dataset" + return tip + + +def dataset_task_status_button_tip(): + tip = "Status dataset" + return tip + + +def map_cif_file_task_tip(): + tip = "describes what you can do" + return tip + + +def map_cif_file_task_run_button_tip(): + tip = "Run map_cif_file" + return tip + + +def map_cif_file_task_status_button_tip(): + tip = "Status map_cif_file" + return tip + + +def panddas_file_task_tip(): + tip = "describes what you can do" + return tip + + +def panddas_file_task_run_button_tip(): + tip = "Run panddas_file" + return tip + + +def panddas_file_task_status_button_tip(): + tip = "Status panddas_file" + return tip + + +def refine_file_task_tip(): + tip = "describes what you can do" + return tip + + +def refine_file_task_run_button_tip(): + tip = "Run refine_file" + return tip + + +def refine_file_task_status_button_tip(): + tip = "Status refine_file" + return tip + + +def update_from_datasource_button_tip(): + tip = "Status validation_file" + return tip + + +def run_pandda_inspect_at_home(pandda_directory): + instruction = ( + "\n\n" + "Be sure to have pandda installed at home, and go to a clean subdirectory.\n" + "From that directory, do the steps below.\n" + "This moves the relevant files to your site so you can do the model building" + " locally, and then moves the files back to Diamond.\n" + "1. run: rsync -av %s@nx.diamond.ac.uk:%s .\n" + % (getpass.getuser(), pandda_directory) + + '2. run: "pandda.inspect", and build all relevant models, etc.\n' + "3. run: rsync -av * %s@nx.diamond.ac.uk:%s\n" + % (getpass.getuser(), pandda_directory) + + "Now proceed within XChemExplorer as before.\n" + ) + + print(instruction) + + +def deposition_interface_note(): + note = ( + "\n\n" + "Note: you can use this mask to save identical information for ALL structures" + " to be deposited.\n" + "However, this may not be suitable in cases where the information is different" + " for certain samples.\n" + "In such cases, please use for example SQLiteBrowser to edit the relevant" + " fields in the depositTable." + ) + + return note + + +def pandda_pre_run(reference_directory): + msg = ( + "The aim of the pre-run is NOT to identify bound ligands,\n" + "but to create mean ground state maps.\n" + "Hence, the pre-run will only comprise 100 datasets.\n" + "After the pre-run is finished use the resulting ground state mean maps\n" + "to build a suitable reference model for the subsequent PanDDA production" + " run.\n" + "The appendix will determine the name of the folder where the results from\n" + "the pre-run will be stored. It is used by the COOT plugin to distinguish\n" + "between different pre-runs.\n" + "The result from the pre-run will be stored in:\n" + "%s/pannda_'https://openlabnotebooks.org/update-on-batch-deposition-of-xchem-structures'" + "" + ) + return lnk + + +def deposition_bound_state_prerequisites(): + msg = ( + "1. Event map to MTZ conversion.\n" + " All pandda event maps need to be converted to MTZ format." + " This is currently not done automatically.\n" + ' If you have not done so, select and run "Event Map -> SF"' + " from the Hit Identification action box.\n" + " This may take a while, but you only need to run this once.\n" + "2. Select datasets to be deposited.\n" + ' Set crystals to "5-ready for deposition" in XCE refinement tab\n' + "3. Enter additional data required for PDB deposition.\n" + ' In the Deposition menu, select "Edit information".' + ' Fill out all the required items and press "Save to Database".\n' + " Note: this needs to be done after the datasets have been selected" + " for deposition." + ) + return msg + + +def deposition_bound_state_preparation_step_one_text(): + msg = ( + "1. Press the button below to generate structure and structure factor mmcif" + " files of all selected datasets.\n" + " Note: all previously generated mmcif files will be overwritten." + ) + return msg + + +def deposition_bound_state_preparation_step_two_text(): + msg = ( + "2. Press the button below to copy all the mmcif files into the" + ' "group deposition directory" (see settings tab).\n' + "All mmcif files will be bundled into a single, bzipped tar archive" + " which can be uploaded into via the PDB group deposition website." + ) + return msg + + +def pdb_group_deposition_instruction_one(): + msg = ( + "3. Go to the group deposition website, create a session and upload the" + " ligand-bound.tar.bz2 file from the group deposition directory." + ) + return msg + + +def pdb_group_deposition_link(): + lnk = ( + "'https://deposit-group-1.rcsb.rutgers.edu/groupdeposit'" + ) + return lnk + + +def pdb_group_deposition_instruction_two(): + msg = " user: grouptester\n" " password: !2016rcsbpdb " + return msg + + +def deposition_ground_state_prerequisites(): + msg = ( + "1. Convert all apo MTZ files to mmcif format.\n" + " Swtich to the pandda tab, select the PanDDA directory which contains the" + " analysis you want to deposit.\n" + ' Then select and run "apo -> mmcif" from the Hit Identification' + " action box.\n" + " Note: you only need to do this once." + ) + return msg + + +def deposition_ground_state_preparation_step_one_text(): + msg = ( + "1. Select ground-state PDB file.\n" + " Note: the file is usually in the reference directory." + ) + return msg + + +def deposition_ground_state_preparation_step_three_text(): + msg = ( + "1. Please check the settings tab that you have selected the correct" + " pandda directory.\n" + " (Note: we will take all the apo mmcif files from this directory)\n" + " Current PanDDA directory:" + ) + return msg + + +def deposition_ground_state_preparation_step_four_text(): + msg = "2. Add the ground-state entry to the database." + return msg + + +def deposition_ground_state_preparation_step_five_text(): + msg = ( + "3. Enter meta-data for ground-state model:\n" + ' - Open "Deposition -> Edit information"\n' + " - Fill out form or load .deposit file\n" + ' - Press "Save to Database"\n' + ' - Press "OK"' + ) + return msg + + +def deposition_ground_state_preparation_step_six_text(): + msg = ( + "4. Prepare the ground-state mmcif file.\n" + " Note: the mmcif files are saved into the selected pandda directory" + ) + return msg + + +def deposition_ground_state_preparation_step_seven_text(): + msg = ( + "5. Press the button below to copy the structire and structure factor mmcif" + ' files into the "group deposition directory" (see settings tab).\n' + "Both mmcif files will be bundled into a single, bzipped tar archive which can" + " be uploaded into via the PDB group deposition website." + ) + return msg + + +def deposition_ground_state_preparation_step_eight_text(): + msg = ( + "6. Go to the group deposition website, create a session and upload the" + " ligand-bound.tar.bz2 file from the group deposition directory." + ) + return msg + + +def after_deposition_step_one_text(): + msg = ( + "After you have successfully submitted the ligand-bound structures via the PDB" + " group deposition interface, you will immediately get\n" + "an email with the PDB codes. There will be a single line for each PDB" + ' submission. Highlight and copy the text! Then go to the "Deposition" menu\n' + 'and select "Update DB with PDB codes". A pop-up window will appear, paste the' + ' text into the window and press "Update Database".' + ) + return msg + + +def deposition_bounnd_state_preparation_ignore_event_map(): + msg = ( + "do NOT include PanDDA event maps" + " (ONLY USE IN CASE IF DATA WERE NOT ANALYSED WITH PANDDA!)" + ) + return msg + + +def second_cif_file_info(cif_file): + second_cif_file = str(cif_file) + if os.path.isfile(second_cif_file): + msg = ( + "You have selected the following restraints file\n" + "for merging into the the ligand CIF files:\n" + second_cif_file + "\n" + "Press NO in case you do not want to continue\n" + "In case you want to use another file, open the preferences menu" + " and set it there\n" + "Please check the XCE logfile in case of unexpected behaviour" + ) + elif second_cif_file.replace(" ", "") == "" or second_cif_file.lower() == "none": + msg = "No restraints file was selected!" + else: + msg = ( + "The selected restraints file does not exist:\n" + second_cif_file + "\n" + "Open the preferences menu and set it there\n" + ) + return msg + + +def second_cif_file_not_exists(): + msg = ( + "The CIF file for the non-standard ligand does not exist! " + "It was either not selected or the file was deleted/ moved in the meantime. " + "Please check Menu -> Preferences." + ) + return msg + + +def notification_about_changes_to_apo_deposition(): + msg = ( + "The ground-state deposition procedure has changes in XCE v1.5.0!\n\n" + "Previously, users had to select a specific reference PDB file," + " which had to have a ground-state mean-map and logfile associated with it.\n" + "However, there were two main problems: (i) the map to mtz conversion" + " did sometimes lead to strange maps or maps in space group P1 only\n" + "and (2) occasionally the resulting MTZ files had missing columns." + " This lead to errors and delays during deposition, while inclusion of\n" + "ground-state mean maps has little benefit since the mean map" + " can be calculated with the deposited apo datasets. Hence, there is really\n" + "no need to include it in the deposition.\n\n" + "All you need to do is to select the relevant PanDDA directory" + " and XCE will arbitrarily select a high resolution structure with low Rfree\n" + "as the model for the deposition bundle and then put all structure factor" + " MMCIF files into a single file. Note that it does not matter\n" + "which PDB file gets chosen at this point since the positional modifications" + " during refinement with REFMAC will be minimal.\n" + "If you still want to make the ground-state mean map available," + " we would recommend to deposit ground-state mean map and \n" + "everything else you think is relevant on ZENODO and ask the PDB annotator to" + " include the respective DOI in the deposition\n" + ) + return msg + + +def pandda_export_ligand_bound_models_only_disclaimer(): + msg = ( + "You have chosen to export and refine the ligand-bound model only. " + "This is different to the original procedure described by" + " Pearce et al. (doi 10.1107/S2059798317003412), " + "which is based on refinement of an ensemble model consisting of ligand-bound" + " state and confounding ground-state." + "Please note that working with the ligand-bound model only usually works well" + " for reasonably well-defined " + "ligands and conformational changes, but it may not be ideal for weakly bound" + " fragments and corresponding " + "conformational changes." + ) + return msg diff --git a/xce/lib/XChemUtils.py b/xce/lib/XChemUtils.py new file mode 100755 index 00000000..08bc376c --- /dev/null +++ b/xce/lib/XChemUtils.py @@ -0,0 +1,2215 @@ +import bz2 +import gzip +import json +import math +import os +import subprocess +import time +from distutils.spawn import find_executable + +from rdkit import Chem + +import gemmi +import iotbx.pdb +from xce.lib import XChemDB +from xce.lib import XChemLog +from iotbx import mtz +from iotbx.reflection_file_reader import any_reflection_file + + +def open_decompress_file(filename, mode="rb"): + """Open file for reading, decompressing silently if necessary.""" + + if filename.endswith(".bz2"): + return bz2.BZ2File(filename, mode=mode) + + elif filename.endswith(".gz"): + return gzip.GzipFile(filename, mode=mode) + + return open(filename, mode=mode) + + +class helpers: + def make_png( + self, + initial_model_directory, + sample, + compoundID, + smiles, + external_software, + database_directory, + data_source_file, + ccp4_scratch_directory, + counter, + xce_logfile, + restraints_program, + ): + Logfile = XChemLog.updateLog(xce_logfile) + + os.system("touch RESTRAINTS_IN_PROGRESS") + + header = "#!" + os.getenv("SHELL") + "\n" + + # check for combisoaks/ cocktails + # note: compoundIDs and smiles are semi-colon separated + if len(compoundID.split(";")) > 1: + Logfile.insert( + "looks like you are working with cocktails;" + " found the following IDs and smiles:" + ) + if len(compoundID.split(";")) != len(smiles.split(";")): + Logfile.error("Number of compoundIDs and SMILES does not match:") + Logfile.error( + "N(compoundID): {0!s} -> {1!s}".format( + len(compoundID.split(";")), compoundID.split(";") + ) + ) + Logfile.error( + "N(SMILES): {0!s} -> {1!s}".format( + len(smiles.split(";")), smiles.split(";") + ) + ) + Logfile.error("aborting...") + return + else: + software = "" + if restraints_program == "acedrg": + if os.getcwd().startswith("/dls"): + software += "module load ccp4/7.1.018\n" + elif restraints_program == "phenix.elbow": + if os.getcwd().startswith("/dls"): + software += "module load ccp4/7.1.018\n" + software += "module load phenix/1.20\n" + elif restraints_program == "grade": + if os.getcwd().startswith("/dls"): + software += "module load ccp4/7.1.018\n" + software += "module load buster/20240123\n" + software += ( + "export BDG_TOOL_MOGUL=" + "/dls_sw/apps/CSDS/2024.1.0/ccdc-software/mogul/bin/mogul" + "\n" + ) + software += "export BDG_TOOL_OBABEL='none'\n" + + for i in range(len(compoundID.split(";"))): + Logfile.insert( + "{0!s} - {1!s}".format( + compoundID.split(";")[i], smiles.split(";")[i] + ) + ) + cID = "L" + (2 - len(str(i))) * "0" + str(i) + if restraints_program == "acedrg": + software += 'acedrg --res {0!s} -i "{1!s}" -o {2!s}\n'.format( + cID, + smiles.split(";")[i], + compoundID.split(";")[i].replace(" ", ""), + ) + elif restraints_program == "phenix.elbow": + software += ( + "phenix.elbow" + + '--smiles="{0!s}" --id {1!s} --output {2!s}\n'.format( + smiles.split(";")[i], + cID, + compoundID.split(";")[i].replace(" ", ""), + ) + ) + elif restraints_program == "grade": + if external_software["mogul"]: + mogul = "" + else: + mogul = "-nomogul" + software += ( + "grade" + + ' -resname {0!s} {1!s} "{2!s}"'.format( + cID, mogul, smiles.split(";")[i] + ) + + " -ocif {0!s}.cif -opdb {1!s}.pdb\n".format( + compoundID.split(";")[i].replace(" ", ""), + compoundID.split(";")[i].replace(" ", ""), + ) + ) + + else: + # check if CompoundSMILEScovalent field is not Null + # CompoundSMILESproduct can be used to create only a CIF file + # for the product to make fitting easier + # however, the complete smiles string will be used to make the png file + productSmiles = None + db = XChemDB.data_source(os.path.join(database_directory, data_source_file)) + sql = ( + "select CompoundSMILESproduct from mainTable where CrystalName = '%s'" + % sample + ) + query = db.execute_statement(sql) + productSmiles = query[0][0] + if str(productSmiles).replace(" ", "") == "": + productSmiles = smiles + elif "none" in str(productSmiles).lower(): + productSmiles = smiles + elif "null" in str(productSmiles).lower(): + productSmiles = smiles + else: + productSmiles = str(productSmiles) + + software = "" + if restraints_program == "acedrg": + software += "module load ccp4/7.1.018\n" + if os.path.isfile( + os.path.join(initial_model_directory, sample, "old.cif") + ): + software += "acedrg --res LIG -c ../old.cif -o {0!s}\n".format( + (compoundID.replace(" ", "")) + ) + else: + software += 'acedrg --res LIG -i "{0!s}" -o {1!s}\n'.format( + productSmiles, compoundID.replace(" ", "") + ) + elif restraints_program == "phenix.elbow": + software += "module load ccp4/7.1.018\n" + software += "module load phenix/1.20\n" + if os.path.isfile( + os.path.join(initial_model_directory, sample, "old.cif") + ): + software += ( + "phenix.elbow --file=../old.cif --id LIG" + + " --output {0!s}\n".format((compoundID.replace(" ", ""))) + ) + else: + software += ( + "phenix.elbow" + + ' --smiles="{0!s}" --id LIG --output {1!s}\n'.format( + productSmiles, compoundID.replace(" ", "") + ) + ) + elif restraints_program == "grade": + software += "module load ccp4/7.1.018\n" + software += "module load buster/20240123\n" + software += ( + "export BDG_TOOL_MOGUL=" + "/dls_sw/apps/CSDS/2024.1.0/ccdc-software/mogul/bin/mogul\n" + ) + software += "export BDG_TOOL_OBABEL='none'\n" + if external_software["mogul"]: + mogul = "" + else: + mogul = "-nomogul" + if os.path.isfile( + os.path.join(initial_model_directory, sample, "old.cif") + ): + software += "grade -resname LIG {0!s}".format( + mogul + ) + " -in ../old.cif -ocif {0!s}.cif -opdb {1!s}.pdb\n".format( + compoundID.replace(" ", ""), compoundID.replace(" ", "") + ) + else: + software += 'grade -resname LIG {0!s} "{1!s}"'.format( + mogul, productSmiles + ) + " -ocif {0!s}.cif -opdb {1!s}.pdb\n".format( + compoundID.replace(" ", ""), + compoundID.replace(" ", ""), + ) + + # merge all compound CIFs into 1 file called merged.cif + software += ( + "$CCP4/bin/ccp4-python" + " $XChemExplorer_DIR/xce/helpers/" + "merge_ligand_cif_files.py {0!s}\n".format( + os.path.join(initial_model_directory, sample, "compound") + ) + ) + + # Removal of the hydrogen atoms in PDB files is required for REFMAC 5 run. + # With hydrogens some ligands fail to pass the external restraints in + # pandda.giant.make_restraints. + # Copy the file with hydrogens to retain in case needed + Cmds = ( + header + "\n" + 'export XChemExplorer_DIR="' + os.getenv("XChemExplorer_DIR") + '"' + "\n" + "module load ccp4/7.1.018\n" + "$CCP4/bin/ccp4-python $XChemExplorer_DIR/xce/helpers/update_status_flag.py" + " {0!s} {1!s} {2!s} {3!s}".format( + os.path.join(database_directory, data_source_file), + sample, + "RefinementCIFStatus", + "running", + ) + + "\n" + '$CCP4/bin/ccp4-python {0!s} "{1!s}" {2!s} {3!s} {4!s}\n'.format( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "create_png_of_compound.py", + ), + smiles, + compoundID.replace(" ", ""), + sample, + initial_model_directory, + ) + + "\n" + "cd " + + os.path.join(initial_model_directory, sample, "compound") + + "\n" + + software + + "\n" + "cd " + os.path.join(initial_model_directory, sample) + "\n" + "ln -s compound/%s.cif .\n" % compoundID.replace(" ", "") + + "ln -s compound/{0!s}.pdb .\n".format(compoundID.replace(" ", "")) + + "ln -s compound/{0!s}.png .\n".format(compoundID.replace(" ", "")) + + "\n" + "$CCP4/bin/ccp4-python " + + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "helpers", + "update_data_source_for_new_cif_files.py", + ) + + " {0!s} {1!s} {2!s} {3!s}\n".format( + os.path.join(database_directory, data_source_file), + sample, + initial_model_directory, + compoundID.replace(" ", ""), + ) + + "\n" + "/bin/rm -f compound/RESTRAINTS_IN_PROGRESS\n" + ) + + os.chdir(ccp4_scratch_directory) + Logfile.insert( + "creating ACEDRG shell script for {0!s},{1!s} in {2!s}".format( + sample, compoundID, ccp4_scratch_directory + ) + ) + f = open("xce_{0!s}_{1!s}.sh".format(restraints_program, str(counter)), "w") + f.write(Cmds) + f.close() + os.system( + "chmod +x xce_{0!s}_{1!s}.sh".format(restraints_program, str(counter)) + ) + + +class parse: + def __init__(self): + self.space_group_dict = { + "triclinic": ["P1"], + "monoclinic_P": ["P2", "P21", "P1211", "P121"], + "monoclinic_C": ["C2", "C121"], + "orthorhombic": [ + "P222", + "P2122", + "P2212", + "P2221", + "P21212", + "P21221", + "P22121", + "P212121", + "C222", + "C2221", + "F222", + "I222", + "I212121", + ], + "tetragonal": [ + "P4", + "P41", + "P42", + "P43", + "I4", + "I41", + "P422", + "P4212", + "P4122", + "P41212", + "P4222", + "P42212", + "P4322", + "P43212", + "I422", + "I4122", + ], + "hexagonal": [ + "P3", + "P31", + "P32", + "P312", + "P321", + "P3112", + "P3121", + "P3212", + "P3221", + "P6", + "P61", + "P65", + "P62", + "P64", + "P63", + "P622", + "P6122", + "P6522", + "P6222", + "P6422", + "P6322", + ], + "rhombohedral": ["H3", "H32"], + "cubic": [ + "P23", + "F23", + "I23", + "P213", + "I213", + "P432", + "P4232", + "F432", + "F4132", + "I432", + "P4332", + "P4132", + "I4132", + ], + } + + self.point_group_dict = { + "1": ["P1"], + "2": ["P2", "P21", "C121", "P1211", "P121", "C2"], + "222": [ + "P222", + "P2122", + "P2212", + "P2221", + "P21212", + "P21221", + "P22121", + "P212121", + "C222", + "C2221", + "F222", + "I222", + "I212121", + ], + "4": ["P4", "P41", "P42", "P43", "I4", "I41"], + "422": [ + "P422", + "P4212", + "P4122", + "P41212", + "P4222", + "P42212", + "P4322", + "P43212", + "I422", + "I4122", + ], + "3": ["P3", "P31", "P32", "H3"], + "32": ["P312", "P321", "P3112", "P3121", "P3212", "P3221", "H32"], + "6": ["P6", "P61", "P65", "P62", "P64", "P63"], + "622": ["P622", "P6122", "P6522", "P6222", "P6422", "P6322"], + "23": ["P23", "F23", "I23", "P213", "I213"], + "432": [ + "P432", + "P4232", + "F432", + "F4132", + "I432", + "P4332", + "P4132", + "I4132", + ], + } + + self.nr_asu_in_unitcell_for_point_group = { + "1": 1, + "2": 2, + "222": 4, + "4": 4, + "422": 8, + "3": 3, + "32": 6, + "6": 6, + "622": 12, + "23": 12, + "432": 24, + } + + self.aimless = { + "DataProcessingProgram": "n/a", + "DataProcessingSpaceGroup": "n/a", + "DataProcessingUnitCell": "n/a", + "DataProcessingA": "n/a", + "DataProcessingB": "n/a", + "DataProcessingC": "n/a", + "DataProcessingAlpha": "n/a", + "DataProcessingBeta": "n/a", + "DataProcessingGamma": "n/a", + "DataProcessingResolutionLow": "n/a", + "DataProcessingResolutionLowInnerShell": "n/a", + "DataProcessingResolutionHigh": "n/a", + "DataProcessingResolutionHighOuterShell": "n/a", + "DataProcessingResolutionOverall": "n/a", + "DataProcessingRmergeOverall": "n/a", + "DataProcessingRmergeLow": "n/a", + "DataProcessingRmergeHigh": "n/a", + "DataProcessingIsigOverall": "n/a", + "DataProcessingIsigLow": "n/a", + "DataProcessingIsigHigh": "n/a", + "DataProcessingCompletenessOverall": "n/a", + "DataProcessingCompletenessLow": "n/a", + "DataProcessingCompletenessHigh": "n/a", + "DataProcessingMultiplicityOverall": "n/a", + "DataProcessingMultiplicityLow": "n/a", + "DataProcessingMultiplicityHigh": "n/a", + "DataProcessingCChalfOverall": "n/a", + "DataProcessingCChalfLow": "n/a", + "DataProcessingCChalfHigh": "n/a", + "DataProcessingResolutionHigh15sigma": "n/a", + "DataProcessingUniqueReflectionsLow": "n/a", + "DataProcessingUniqueReflectionsHigh": "n/a", + "DataProcessingUniqueReflectionsOverall": "n/a", + "DataProcessingLattice": "n/a", + "DataProcessingPointGroup": "n/a", + "DataProcessingUnitCellVolume": 0, + "DataProcessingAlert": "#FF0000", + "DataCollectionWavelength": "n/a", + "DataProcessingScore": "n/a", + } + + def read_aimless_logfile(self, logfile): + # essentially same as above, but compatible with datasource + # will hopefully supersede function above + + a = "n/a" + b = "n/a" + c = "n/a" + alpha = "n/a" + beta = "n/a" + gamma = "n/a" + + if "fast_dp" in logfile: + self.aimless["DataProcessingProgram"] = "fast_dp" + elif "3d-run" in logfile: + self.aimless["DataProcessingProgram"] = "xia2-3d" + elif "3dii-run" in logfile: + self.aimless["DataProcessingProgram"] = "xia2-3dii" + elif "xia2-3dii" in logfile: + self.aimless["DataProcessingProgram"] = "xia2-3dii" + elif "dials-run" in logfile: + self.aimless["DataProcessingProgram"] = "dials" + elif "dials" in logfile: + self.aimless["DataProcessingProgram"] = "dials" + elif "autoPROC" in logfile: + self.aimless["DataProcessingProgram"] = "autoPROC" + elif "staraniso" in logfile: + self.aimless["DataProcessingProgram"] = "aP_staraniso" + + # get run number from logfile + # only works if file is in original directory, but not once it moved to + # 'inital_model' folder + + if logfile.endswith(".log") or logfile.endswith(".table1"): + self.aimless_logile(logfile) + elif logfile.endswith(".json"): + self.json_logfile(logfile) + + if ( + self.aimless["DataProcessingA"] != "n/a" + and self.aimless["DataProcessingB"] != "n/a" + and self.aimless["DataProcessingC"] != "n/a" + and self.aimless["DataProcessingAlpha"] != "n/a" + and self.aimless["DataProcessingBeta"] != "n/a" + and self.aimless["DataProcessingGamma"] != "n/a" + and self.aimless["DataProcessingLattice"] != "n/a" + ): + a = self.aimless["DataProcessingA"] + b = self.aimless["DataProcessingB"] + c = self.aimless["DataProcessingC"] + alpha = self.aimless["DataProcessingAlpha"] + beta = self.aimless["DataProcessingBeta"] + gamma = self.aimless["DataProcessingGamma"] + self.aimless["DataProcessingUnitCellVolume"] = str( + self.calc_unitcell_volume_from_logfile( + float(a), + float(b), + float(c), + math.radians(float(alpha)), + math.radians(float(beta)), + math.radians(float(gamma)), + self.aimless["DataProcessingLattice"], + ) + ) + try: + high_symmetry_boost = self.nr_asu_in_unitcell_for_point_group[ + self.aimless["DataProcessingPointGroup"] + ] + self.aimless["DataProcessingScore"] = ( + float(self.aimless["DataProcessingUniqueReflectionsOverall"]) + * float(self.aimless["DataProcessingCompletenessOverall"]) + * high_symmetry_boost + * float(self.aimless["DataProcessingIsigOverall"]) + ) / float(self.aimless["DataProcessingUnitCellVolume"]) + # When P-6 was accidentally used self.aimless['DataProcessingPointGroup'] + # through a KeyError, so handling this + except (ValueError, KeyError): + self.aimless["DataProcessingScore"] = 0.0 + self.aimless["DataProcessingUnitCell"] = ( + str(a) + + " " + + str(b) + + " " + + str(c) + + " " + + str(alpha) + + " " + + str(beta) + + " " + + str(gamma) + ) + self.aimless["DataProcessingResolutionOverall"] = ( + str(self.aimless["DataProcessingResolutionLow"]) + + " - " + + str(self.aimless["DataProcessingResolutionHigh"]) + ) + + if ( + self.aimless["DataProcessingResolutionHigh"] == "n/a" + or self.aimless["DataProcessingRmergeLow"] == "n/a" + ): + self.aimless["DataProcessingAlert"] = "#FF0000" + else: + if ( + float(self.aimless["DataProcessingResolutionHigh"]) > 3.5 + or float(self.aimless["DataProcessingRmergeLow"]) > 0.1 + ): + self.aimless["DataProcessingAlert"] = "#FF0000" + if (3.5 >= float(self.aimless["DataProcessingResolutionHigh"]) > 2.5) or ( + 0.1 >= float(self.aimless["DataProcessingRmergeLow"]) > 0.05 + ): + self.aimless["DataProcessingAlert"] = "#FF9900" + if ( + float(self.aimless["DataProcessingResolutionHigh"]) <= 2.5 + and float(self.aimless["DataProcessingRmergeLow"]) <= 0.05 + ): + self.aimless["DataProcessingAlert"] = "#00FF00" + + return self.aimless + + def aimless_logile(self, logfile): + resolution_at_15_sigma_line_overall_found = False + resolution_at_20_sigma_line_overall_found = False + for _, line in enumerate(open(logfile)): + if "Wavelength" in line and len(line.split()) >= 2: + self.aimless["DataCollectionWavelength"] = line.split()[1] + if "Low resolution limit" in line and len(line.split()) == 6: + self.aimless["DataProcessingResolutionLow"] = line.split()[3] + self.aimless["DataProcessingResolutionHighOuterShell"] = line.split()[5] + if "High resolution limit" in line and len(line.split()) == 6: + self.aimless["DataProcessingResolutionHigh"] = line.split()[3] + self.aimless["DataProcessingResolutionLowInnerShell"] = line.split()[4] + if "Rmerge (all I+ and I-)" in line and len(line.split()) == 8: + self.aimless["DataProcessingRmergeOverall"] = line.split()[5] + self.aimless["DataProcessingRmergeLow"] = line.split()[6] + self.aimless["DataProcessingRmergeHigh"] = line.split()[7] + if "Rmerge (all I+ & I-)" in line and len(line.split()) == 8: + self.aimless["DataProcessingRmergeOverall"] = line.split()[5] + self.aimless["DataProcessingRmergeLow"] = line.split()[6] + self.aimless["DataProcessingRmergeHigh"] = line.split()[7] + if "Mean((I)/sd(I))" in line and len(line.split()) == 4: + self.aimless["DataProcessingIsigOverall"] = line.split()[1] + self.aimless["DataProcessingIsigHigh"] = line.split()[3] + self.aimless["DataProcessingIsigLow"] = line.split()[2] + if "Mean(I)/sd(I)" in line and len(line.split()) == 4: + self.aimless["DataProcessingIsigOverall"] = line.split()[1] + self.aimless["DataProcessingIsigHigh"] = line.split()[3] + self.aimless["DataProcessingIsigLow"] = line.split()[2] + if line.startswith("Completeness") and len(line.split()) == 4: + self.aimless["DataProcessingCompletenessOverall"] = line.split()[1] + self.aimless["DataProcessingCompletenessHigh"] = line.split()[3] + self.aimless["DataProcessingCompletenessLow"] = line.split()[2] + if "Completeness (ellipsoidal)" in line and len(line.split()) == 5: + self.aimless["DataProcessingCompletenessOverall"] = line.split()[2] + self.aimless["DataProcessingCompletenessHigh"] = line.split()[4] + self.aimless["DataProcessingCompletenessLow"] = line.split()[3] + if "Multiplicity" in line and len(line.split()) == 4: + self.aimless["DataProcessingMultiplicityOverall"] = line.split()[1] + self.aimless["DataProcessingMultiplicityHigh"] = line.split()[3] + self.aimless["DataProcessingMultiplicityLow"] = line.split()[3] + if ( + line.startswith("Mn(I) half-set correlation CC(1/2)") + and len(line.split()) == 7 + ): + self.aimless["DataProcessingCChalfOverall"] = line.split()[4] + self.aimless["DataProcessingCChalfLow"] = line.split()[5] + self.aimless["DataProcessingCChalfHigh"] = line.split()[6] + if line.startswith(" CC(1/2)") and len(line.split()) == 4: + self.aimless["DataProcessingCChalfOverall"] = line.split()[1] + self.aimless["DataProcessingCChalfLow"] = line.split()[2] + self.aimless["DataProcessingCChalfHigh"] = line.split()[3] + if line.startswith("Estimates of resolution limits: overall"): + resolution_at_15_sigma_line_overall_found = True + resolution_at_20_sigma_line_overall_found = True + if resolution_at_15_sigma_line_overall_found: + if "from Mn(I/sd)" in line and len(line.split()) >= 7: + if "1.5" in line.split()[3]: + self.aimless[ + "DataProcessingResolutionHigh15sigma" + ] = line.split()[6][:-1] + resolution_at_15_sigma_line_overall_found = False + if resolution_at_20_sigma_line_overall_found: + if "from Mn(I/sd)" in line and len(line.split()) >= 7: + if "2.0" in line.split()[3]: + self.aimless[ + "DataProcessingResolutionHigh20sigma" + ] = line.split()[6][:-1] + resolution_at_20_sigma_line_overall_found = False + if ( + line.startswith("Average unit cell:") + or line.startswith(" Unit cell parameters") + ) and len(line.split()) == 9: + tmp = [line.split()] + a = int(float(tmp[0][3])) + b = int(float(tmp[0][4])) + c = int(float(tmp[0][5])) + alpha = int(float(tmp[0][6])) + beta = int(float(tmp[0][7])) + gamma = int(float(tmp[0][8])) + self.aimless["DataProcessingA"] = str(a) + self.aimless["DataProcessingB"] = str(b) + self.aimless["DataProcessingC"] = str(c) + self.aimless["DataProcessingAlpha"] = str(alpha) + self.aimless["DataProcessingBeta"] = str(beta) + self.aimless["DataProcessingGamma"] = str(gamma) + if "Total number unique" in line and len(line.split()) == 6: + self.aimless["DataProcessingUniqueReflectionsOverall"] = line.split()[3] + if line.startswith("Space group:") or line.startswith(" Spacegroup name"): + if "Laue" in line: + continue + if "Spacegroup name" in line: + self.aimless["DataProcessingSpaceGroup"] = line.replace( + " Spacegroup name", "" + )[:-1].replace(" ", "") + else: + self.aimless["DataProcessingSpaceGroup"] = line.replace( + "Space group: ", "" + )[:-1] + self.aimless[ + "DataProcessingLattice" + ] = self.get_lattice_from_space_group( + self.aimless["DataProcessingSpaceGroup"] + ) + self.aimless[ + "DataProcessingPointGroup" + ] = self.get_pointgroup_from_space_group( + self.aimless["DataProcessingSpaceGroup"] + ) + + def json_logfile(self, logfile): + with open(logfile, "r") as log: + data = log.read() + obj = json.loads(data) + self.aimless["DataProcessingResolutionLow"] = str( + round(math.sqrt(1 / float(obj["d_star_sq_max"][0])), 2) + ) + self.aimless["DataProcessingResolutionLowInnerShell"] = str( + round(math.sqrt(1 / float(obj["d_star_sq_max"][1])), 2) + ) + self.aimless["DataProcessingResolutionHigh"] = str( + round( + math.sqrt( + 1 / float(obj["d_star_sq_min"][len(obj["d_star_sq_min"]) - 1]) + ), + 2, + ) + ) + self.aimless["DataProcessingResolutionHighOuterShell"] = str( + round( + math.sqrt( + 1 / float(obj["d_star_sq_min"][len(obj["d_star_sq_min"]) - 2]) + ), + 2, + ) + ) + self.aimless["DataProcessingResolutionOverall"] = ( + self.aimless["DataProcessingResolutionLow"] + + "-" + + self.aimless["DataProcessingResolutionHigh"] + ) + self.aimless["DataProcessingRmergeOverall"] = str( + round(obj["overall"]["r_merge"], 3) + ) + self.aimless["DataProcessingRmergeLow"] = str(round(obj["r_merge"][0], 3)) + self.aimless["DataProcessingRmergeHigh"] = str( + round(obj["r_merge"][len(obj["r_merge"]) - 1], 3) + ) + self.aimless["DataProcessingIsigOverall"] = str( + round(obj["overall"]["i_over_sigma_mean"], 1) + ) + self.aimless["DataProcessingIsigLow"] = str( + round(obj["i_over_sigma_mean"][0], 1) + ) + self.aimless["DataProcessingIsigHigh"] = str( + round(obj["i_over_sigma_mean"][len(obj["i_over_sigma_mean"]) - 1], 1) + ) + self.aimless["DataProcessingCompletenessOverall"] = str( + round(obj["overall"]["completeness"], 1) + ) + self.aimless["DataProcessingCompletenessLow"] = str( + round(obj["completeness"][0], 1) + ) + self.aimless["DataProcessingCompletenessHigh"] = str( + round(obj["completeness"][len(obj["completeness"]) - 1], 1) + ) + self.aimless["DataProcessingMultiplicityOverall"] = str( + round(obj["overall"]["multiplicity"], 1) + ) + self.aimless["DataProcessingMultiplicityLow"] = str( + round(obj["multiplicity"][0], 1) + ) + self.aimless["DataProcessingMultiplicityHigh"] = str( + round(obj["multiplicity"][len(obj["multiplicity"]) - 1], 1) + ) + self.aimless["DataProcessingCChalfOverall"] = str( + round(obj["overall"]["cc_one_half"], 2) + ) + self.aimless["DataProcessingCChalfLow"] = str(round(obj["cc_one_half"][0], 2)) + self.aimless["DataProcessingCChalfHigh"] = str( + round(obj["cc_one_half"][len(obj["cc_one_half"]) - 1], 2) + ) + + self.aimless["DataProcessingUniqueReflectionsLow"] = str(obj["n_uniq"][0]) + self.aimless["DataProcessingUniqueReflectionsHigh"] = str( + obj["n_uniq"][len(obj["n_uniq"]) - 1] + ) + + self.aimless["DataProcessingUniqueReflectionsOverall"] = str( + obj["overall"]["n_obs"] + ) + json_name = logfile[logfile.rfind("/") + 1 :] + mmcif_file = logfile.replace("LogFiles", "DataFiles").replace( + json_name, "xia2.mmcif" + ) + if os.path.isfile(mmcif_file): + self.read_mmcif(mmcif_file) + elif os.path.isfile("%s.bz2" % mmcif_file): + self.read_mmcif("%s.bz2" % mmcif_file) + + def make_pseudo_aimless_log_from_json(self, logfile): + self.json_logfile(logfile) + template = ( + "==============================================================\n" + "\n" + " $TEXT:Result: $$ $$\n" + "Summary data for" + " Project: nt11175v63" + " Crystal: xPHIPAx17245" + " Dataset: SAD\n" + "\n" + " " + "Overall InnerShell OuterShell\n" + "Low resolution limit" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingResolutionLow"], + self.aimless["DataProcessingResolutionLow"], + self.aimless["DataProcessingResolutionHighOuterShell"], + ) + + "High resolution limit" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingResolutionHigh"], + self.aimless["DataProcessingResolutionLowInnerShell"], + self.aimless["DataProcessingResolutionHigh"], + ) + + "\n" + "Rmerge (within I+/I-)" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingRmergeOverall"], + self.aimless["DataProcessingRmergeLow"], + self.aimless["DataProcessingRmergeHigh"], + ) + + "Rmerge (all I+ and I-)" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingRmergeOverall"], + self.aimless["DataProcessingRmergeLow"], + self.aimless["DataProcessingRmergeHigh"], + ) + + "Rmeas (within I+/I-) - - - \n" + "Rmeas (all I+ & I-) - - - \n" + "Rpim (within I+/I-) - - - \n" + "Rpim (all I+ & I-) - - - \n" + "Rmerge in top intensity bin - - - \n" + "Total number of observations - - - \n" + "Total number unique" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingUniqueReflectionsOverall"], + self.aimless["DataProcessingUniqueReflectionsLow"], + self.aimless["DataProcessingUniqueReflectionsHigh"], + ) + + "Mean((I)/sd(I))" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingIsigOverall"], + self.aimless["DataProcessingIsigLow"], + self.aimless["DataProcessingIsigHigh"], + ) + + "Mn(I) half-set correlation CC(1/2)" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingCChalfOverall"], + self.aimless["DataProcessingCChalfLow"], + self.aimless["DataProcessingCChalfHigh"], + ) + + "Completeness" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingCompletenessOverall"], + self.aimless["DataProcessingCompletenessLow"], + self.aimless["DataProcessingCompletenessHigh"], + ) + + "Multiplicity" + " {0!s} {1!s} {2!s}\n".format( + self.aimless["DataProcessingMultiplicityOverall"], + self.aimless["DataProcessingMultiplicityLow"], + self.aimless["DataProcessingMultiplicityHigh"], + ) + ) + f = open("aimless_dials.log", "w") + f.write(template) + f.close() + + def read_mmcif(self, mmcif): + for line in open_decompress_file(mmcif): + if line.startswith("_cell.angle_alpha "): + self.aimless["DataProcessingAlpha"] = line.split()[1] + elif line.startswith("_cell.angle_beta "): + self.aimless["DataProcessingBeta"] = line.split()[1] + elif line.startswith("_cell.angle_gamma "): + self.aimless["DataProcessingGamma"] = line.split()[1] + elif line.startswith("_cell.length_a "): + self.aimless["DataProcessingA"] = line.split()[1] + elif line.startswith("_cell.length_b "): + self.aimless["DataProcessingB"] = line.split()[1] + elif line.startswith("_cell.length_c "): + self.aimless["DataProcessingC"] = line.split()[1] + elif line.startswith("_diffrn_radiation_wavelength.wavelength"): + self.aimless["DataCollectionWavelength"] = line.split()[1] + elif line.startswith("_symmetry.space_group_name_H-M"): + self.aimless["DataProcessingSpaceGroup"] = line[ + line.find("'") + 1 : line.rfind("'") + ].replace(" ", "") + if "R32:H" in self.aimless["DataProcessingSpaceGroup"]: + self.aimless["DataProcessingSpaceGroup"] = "H32" + if "R3:H" in self.aimless["DataProcessingSpaceGroup"]: + self.aimless["DataProcessingSpaceGroup"] = "H3" + self.aimless[ + "DataProcessingPointGroup" + ] = self.get_pointgroup_from_space_group( + self.aimless["DataProcessingSpaceGroup"] + ) + elif line.startswith("_space_group.crystal_system"): + self.aimless["DataProcessingLattice"] = line.split()[1] + if self.aimless["DataProcessingLattice"] == "trigonal": + self.aimless["DataProcessingLattice"] = "hexagonal" + self.aimless["DataProcessingUnitCell"] = ( + self.aimless["DataProcessingA"] + + " " + + self.aimless["DataProcessingA"] + + " " + + self.aimless["DataProcessingA"] + + " " + + self.aimless["DataProcessingA"] + + " " + + self.aimless["DataProcessingA"] + + " " + + self.aimless["DataProcessingA"] + ) + + def get_lattice_from_space_group(self, logfile_spacegroup): + lattice_type = "n/a" + for lattice in self.space_group_dict: + for spacegroup in self.space_group_dict[lattice]: + if logfile_spacegroup.replace(" ", "") == spacegroup: + lattice_type = lattice + break + return lattice_type + + def get_pointgroup_from_space_group(self, logfile_spacegroup): + pointgroup = "n/a" + for pg in self.point_group_dict: + for spacegroup in self.point_group_dict[pg]: + if logfile_spacegroup.replace(" ", "") == spacegroup: + pointgroup = pg + break + return pointgroup + + def calc_unitcell_volume_from_logfile(self, a, b, c, alpha, beta, gamma, lattice): + unitcell_volume = 0 + if lattice == "triclinic": + unitcell_volume = ( + a + * b + * c + * math.sqrt( + ( + 1 + - math.cos(alpha) ** 2 + - math.cos(beta) ** 2 + - math.cos(gamma) ** 2 + ) + + 2 * (math.cos(alpha) * math.cos(beta) * math.cos(gamma)) + ) + ) + if "monoclinic" in lattice: + unitcell_volume = round(a * b * c * math.sin(beta), 1) + if lattice == "orthorhombic" or lattice == "tetragonal" or lattice == "cubic": + unitcell_volume = round(a * b * c, 1) + if lattice == "hexagonal" or lattice == "rhombohedral": + unitcell_volume = round(a * b * c * (math.sin(math.radians(60))), 1) + return unitcell_volume + + def PDBheader(self, pdbfile): + PDBinfo = { + "Rcryst": "n/a", + "RcrystTL": "gray", + "Rfree": "n/a", + "RfreeTL": "gray", + "SpaceGroup": "n/a", + "PointGroup": "n/a", + "UnitCell": "n/a", + "ResolutionHigh": "n/a", + "ResolutionColor": "gray", + "Lattice": "n/a", + "UnitCellVolume": 0, + "Alert": "#E0E0E0", + "rmsdBonds": "n/a", + "rmsdBondsTL": "gray", + "rmsdAngles": "n/a", + "rmsdAnglesTL": "gray", + "TwinFraction": "n/a", + } + + a = "n/a" + b = "n/a" + c = "n/a" + alpha = "n/a" + beta = "n/a" + gamma = "n/a" + + if os.path.isfile(pdbfile): + for line in open(pdbfile): + try: + if line.startswith( + "REMARK 3 R VALUE (WORKING + TEST SET) :" + ): + PDBinfo["Rcryst"] = line.split()[9] + if float(PDBinfo["Rcryst"]) > 0.4: + PDBinfo["Alert"] = "#FF0000" + PDBinfo["RcrystTL"] = "red" + if 0.4 >= float(PDBinfo["Rcryst"]) >= 0.3: + PDBinfo["Alert"] = "#FF9900" + PDBinfo["RcrystTL"] = "orange" + if float(PDBinfo["Rcryst"]) < 0.3: + PDBinfo["Alert"] = "#00FF00" + PDBinfo["RcrystTL"] = "green" + if line.startswith( + "REMARK 3 FREE R VALUE :" + ): + PDBinfo["Rfree"] = line.split()[6] + if float(PDBinfo["Rfree"]) > 0.4: + PDBinfo["Alert"] = "#FF0000" + PDBinfo["RfreeTL"] = "red" + if 0.4 >= float(PDBinfo["Rfree"]) >= 0.3: + PDBinfo["Alert"] = "#FF9900" + PDBinfo["RfreeTL"] = "orange" + if float(PDBinfo["Rfree"]) < 0.3: + PDBinfo["Alert"] = "#00FF00" + PDBinfo["RfreeTL"] = "green" + except ValueError: + pass + + if line.startswith("REMARK 3 RESOLUTION RANGE HIGH (ANGSTROMS) :"): + PDBinfo["ResolutionHigh"] = line.split()[7] + try: + if float(line.split()[7]) < 2.4: + PDBinfo["ResolutionColor"] = "green" + if 2.4 <= float(line.split()[7]) < 2.8: + PDBinfo["ResolutionColor"] = "orange" + if float(line.split()[7]) >= 2.8: + PDBinfo["ResolutionColor"] = "red" + except ValueError: + pass + if line.startswith( + "REMARK 3 BOND LENGTHS REFINED ATOMS (A):" + ): + PDBinfo["rmsdBonds"] = line.split()[9] + try: + if float(line.split()[9]) < 0.02: + PDBinfo["rmsdBondsTL"] = "green" + if 0.02 <= float(line.split()[9]) < 0.03: + PDBinfo["rmsdBondsTL"] = "orange" + if float(line.split()[9]) >= 0.03: + PDBinfo["rmsdBondsTL"] = "red" + except ValueError: + pass + if line.startswith( + "REMARK 3 BOND ANGLES REFINED ATOMS (DEGREES):" + ): + PDBinfo["rmsdAngles"] = line.split()[9] + try: + if float(line.split()[9]) < 2.0: + PDBinfo["rmsdAnglesTL"] = "green" + if 2.0 <= float(line.split()[9]) < 3.0: + PDBinfo["rmsdAnglesTL"] = "orange" + if float(line.split()[9]) >= 3.0: + PDBinfo["rmsdAnglesTL"] = "red" + except ValueError: + pass + + if line.startswith("REMARK 3 TWIN FRACTION"): + try: + PDBinfo["TwinFraction"] = line.split()[5] + except IndexError: + pass + + if line.startswith("CRYST1"): + a = int(float(line.split()[1])) + b = int(float(line.split()[2])) + c = int(float(line.split()[3])) + alpha = int(float(line.split()[4])) + beta = int(float(line.split()[5])) + gamma = int(float(line.split()[6])) + + PDBinfo["UnitCell"] = ( + line.split()[1] + + " " + + line.split()[2] + + " " + + line.split()[3] + + " " + + line.split()[4] + + " " + + line.split()[5] + + " " + + line.split()[6] + ) + + PDBinfo["SpaceGroup"] = str(line[55:65]).rstrip() + + PDBinfo["Lattice"] = self.get_lattice_from_space_group( + PDBinfo["SpaceGroup"] + ) + PDBinfo["PointGroup"] = self.get_pointgroup_from_space_group( + PDBinfo["SpaceGroup"] + ) + if ( + a != "n/a" + and b != "n/a" + and c != "n/a" + and alpha != "n/a" + and beta != "n/a" + and gamma != "n/a" + and PDBinfo["Lattice"] != "n/a" + ): + PDBinfo[ + "UnitCellVolume" + ] = self.calc_unitcell_volume_from_logfile( + float(a), + float(b), + float(c), + math.radians(float(alpha)), + math.radians(float(beta)), + math.radians(float(gamma)), + PDBinfo["Lattice"], + ) + + return PDBinfo + + def dict_for_datasource_update(self, pdbfile): + pdb = self.PDBheader(pdbfile) + db_dict = { + "RefinementPDB_latest": os.path.realpath(pdbfile), + "RefinementRcryst": pdb["Rcryst"], + "RefinementRcrystTraficLight": pdb["RcrystTL"], + "RefinementRfree": pdb["Rfree"], + "RefinementRfreeTraficLight": pdb["RfreeTL"], + "RefinementRmsdBonds": pdb["rmsdBonds"], + "RefinementRmsdBondsTL": pdb["rmsdBondsTL"], + "RefinementRmsdAngles": pdb["rmsdAngles"], + "RefinementRmsdAnglesTL": pdb["rmsdAnglesTL"], + "RefinementSpaceGroup": pdb["SpaceGroup"], + "RefinementResolution": pdb["ResolutionHigh"], + "RefinementResolutionTL": pdb["ResolutionColor"], + } + return db_dict + + def update_datasource_with_PDBheader(self, xtal, datasource, pdbfile): + pdb = self.PDBheader(pdbfile) + db_dict = { + "RefinementPDB_latest": os.path.realpath(pdbfile), + "RefinementRcryst": pdb["Rcryst"], + "RefinementRcrystTraficLight": pdb["RcrystTL"], + "RefinementRfree": pdb["Rfree"], + "RefinementRfreeTraficLight": pdb["RfreeTL"], + "RefinementRmsdBonds": pdb["rmsdBonds"], + "RefinementRmsdBondsTL": pdb["rmsdBondsTL"], + "RefinementRmsdAngles": pdb["rmsdAngles"], + "RefinementRmsdAnglesTL": pdb["rmsdAnglesTL"], + "RefinementSpaceGroup": pdb["SpaceGroup"], + "RefinementResolution": pdb["ResolutionHigh"], + "RefinementResolutionTL": pdb["ResolutionColor"], + } + print(db_dict) + db = XChemDB.data_source(datasource) + db.update_data_source(xtal, db_dict) + + def update_datasource_with_phenix_validation_summary( + self, xtal, datasource, validation_summary + ): + db_dict = {} + if os.path.isfile(validation_summary): + for line in open(validation_summary): + if "molprobity score" in line.lower(): + if len(line.split()) >= 4: + db_dict["RefinementMolProbityScore"] = line.split()[3] + if float(line.split()[3]) < 2: + db_dict["RefinementMolProbityScoreTL"] = "green" + if 2 <= float(line.split()[3]) < 3: + db_dict["RefinementMolProbityScoreTL"] = "orange" + if float(line.split()[3]) >= 3: + db_dict["RefinementMolProbityScoreTL"] = "red" + + if "ramachandran outliers" in line.lower(): + if len(line.split()) >= 4: + db_dict["RefinementRamachandranOutliers"] = line.split()[3] + if float(line.split()[3]) < 0.3: + db_dict["RefinementRamachandranOutliersTL"] = "green" + if 0.3 <= float(line.split()[3]) < 1: + db_dict["RefinementRamachandranOutliersTL"] = "orange" + if float(line.split()[3]) >= 1: + db_dict["RefinementRamachandranOutliersTL"] = "red" + + if "favored" in line.lower(): + if len(line.split()) >= 3: + db_dict["RefinementRamachandranFavored"] = line.split()[2] + if float(line.split()[2]) < 90: + db_dict["RefinementRamachandranFavoredTL"] = "red" + if 90 <= float(line.split()[2]) < 98: + db_dict["RefinementRamachandranFavoredTL"] = "orange" + if float(line.split()[2]) >= 98: + db_dict["RefinementRamachandranFavoredTL"] = "green" + else: + db_dict["RefinementMolProbityScore"] = "-" + db_dict["RefinementMolProbityScoreTL"] = "gray" + db_dict["RefinementRamachandranOutliers"] = "-" + db_dict["RefinementRamachandranOutliersTL"] = "gray" + db_dict["RefinementRamachandranFavored"] = "-" + db_dict["RefinementRamachandranFavoredTL"] = "gray" + db = XChemDB.data_source(datasource) + db.update_data_source(xtal, db_dict) + + +class mtztools: + def __init__(self, mtzfile): + self.mtzfile = mtzfile + self.hkl = any_reflection_file(file_name=self.mtzfile) + self.miller_arrays = self.hkl.as_miller_arrays() + self.mtz = self.miller_arrays[0] + self.iotbxMTZ = mtz.object(self.mtzfile) + + self.space_group_dict = { + "triclinic": [1], + "monoclinic_P": [3, 4], + "monoclinic_C": [5], + "orthorhombic": [16, 17, 18, 19, 20, 21, 22, 23, 24], + "tetragonal": [ + 75, + 76, + 77, + 78, + 79, + 80, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + ], + "hexagonal": [ + 143, + 144, + 145, + 149, + 150, + 151, + 152, + 153, + 154, + 168, + 169, + 170, + 171, + 172, + 173, + 177, + 178, + 179, + 180, + 181, + 182, + ], + "rhombohedral": [146, 155], + "cubic": [195, 196, 197, 198, 199, 207, 208, 209, 210, 211, 212, 213, 214], + } + + self.point_group_dict = { + "1": [1], + "2": [3, 4, 5], + "222": [16, 17, 18, 19, 20, 21, 22, 23, 24], + "4": [75, 76, 77, 78, 79, 80], + "422": [89, 90, 91, 92, 93, 94, 95, 96, 97, 98], + "3": [143, 144, 145, 146], + "32": [149, 150, 151, 152, 153, 154, 155], + "6": [168, 169, 170, 171, 172, 173], + "622": [177, 178, 179, 180, 181, 182], + "23": [195, 196, 197, 198, 199], + "432": [207, 208, 209, 210, 211, 212, 213, 214], + } + + self.nr_asu_in_unitcell_for_point_group = { + "1": 1, + "2": 2, + "222": 4, + "4": 4, + "422": 8, + "3": 3, + "32": 6, + "6": 6, + "622": 12, + "23": 12, + "432": 24, + } + + self.aimless = { + "DataProcessingProgram": "n/a", + "DataProcessingSpaceGroup": "n/a", + "DataProcessingUnitCell": "n/a", + "DataProcessingA": "n/a", + "DataProcessingB": "n/a", + "DataProcessingC": "n/a", + "DataProcessingAlpha": "n/a", + "DataProcessingBeta": "n/a", + "DataProcessingGamma": "n/a", + "DataProcessingResolutionLow": "n/a", + "DataProcessingResolutionLowInnerShell": "n/a", + "DataProcessingResolutionHigh": "n/a", + "DataProcessingResolutionHighOuterShell": "n/a", + "DataProcessingResolutionOverall": "n/a", + "DataProcessingRmergeOverall": "n/a", + "DataProcessingRmergeLow": "n/a", + "DataProcessingRmergeHigh": "n/a", + "DataProcessingIsigOverall": "n/a", + "DataProcessingIsigLow": "n/a", + "DataProcessingIsigHigh": "n/a", + "DataProcessingCompletenessOverall": "n/a", + "DataProcessingCompletenessLow": "n/a", + "DataProcessingCompletenessHigh": "n/a", + "DataProcessingMultiplicityOverall": "n/a", + "DataProcessingMultiplicityLow": "n/a", + "DataProcessingMultiplicityHigh": "n/a", + "DataProcessingCChalfOverall": "n/a", + "DataProcessingCChalfLow": "n/a", + "DataProcessingCChalfHigh": "n/a", + "DataProcessingResolutionHigh15sigma": "n/a", + "DataProcessingUniqueReflectionsOverall": "n/a", + "DataProcessingLattice": "n/a", + "DataProcessingPointGroup": "n/a", + "DataProcessingUnitCellVolume": 0, + "DataProcessingAlert": "#FF0000", + "DataCollectionWavelength": "n/a", + "DataProcessingScore": "n/a", + } + + def get_dmin(self): + return str(round(float(self.mtz.d_min()), 2)) + + def get_wavelength(self): + wavelength = 0.0 + for crystal in self.iotbxMTZ.crystals(): + for dataset in crystal.datasets(): + if not dataset.wavelength() == 0.0: + wavelength = str(round(dataset.wavelength(), 5)) + break + return wavelength + + def get_information_for_datasource(self): + db_dict = {} + mtz_dict = self.get_all_values_as_dict() + pg = self.get_pointgroup_from_mtz() + if mtz_dict != {}: + db_dict["DataProcessingResolutionHigh"] = mtz_dict["resolution_high"] + db_dict["DataProcessingUnitCell"] = mtz_dict["unitcell"] + db_dict["DataProcessingSpaceGroup"] = mtz_dict["spacegroup"] + db_dict["DataProcessingUnitCellVolume"] = mtz_dict["unitcell_volume"] + db_dict["DataProcessingLattice"] = mtz_dict["bravais_lattice"] + if pg != "": + db_dict["DataProcessingPointGroup"] = pg + return db_dict + + def get_bravais_lattice_from_spg_number(self, number): + lattice = "" + for bravaislattice in self.space_group_dict: + for spg_number in self.space_group_dict[bravaislattice]: + if spg_number == number: + lattice = bravaislattice + return lattice + + def get_point_group_from_spg_number(self, number): + pointgroup = "" + for pg in self.point_group_dict: + for spg_number in self.point_group_dict[pg]: + if spg_number == number: + pointgroup = pg + return pointgroup + + def get_spg_number_from_mtz(self): + spg_number = 0 + mtzdmp = subprocess.Popen(["mtzdmp", self.mtzfile], stdout=subprocess.PIPE) + for n, line in enumerate(iter(mtzdmp.stdout.readline, "")): + if line.startswith(" * Space group ="): + spg_number = int(line[line.rfind(")") - 3 : line.rfind(")")]) + return spg_number + + def get_pointgroup_from_mtz(self): + pointgroup = "" + spg_number = self.get_spg_number_from_mtz() + pointgroup = self.get_point_group_from_spg_number(spg_number) + return pointgroup + + def get_number_measured_reflections(self): + missing_reflections = "0" + all_reflections = "0" + meassured_reflections = "0" + mtzdmp = subprocess.Popen(["mtzdmp", self.mtzfile], stdout=subprocess.PIPE) + foundTable = False + for n, line in enumerate(iter(mtzdmp.stdout.readline, "")): + if line.startswith( + " Col Sort Min Max Num %" + " Mean Mean Resolution Type Column" + ): + foundTable = True + if foundTable and len(line.split()) == 12: + if line.split()[11] == "F": + missing_reflections = line.split()[4] + foundTable = False + if line.startswith(" No. of reflections used in FILE STATISTICS"): + all_reflections = line.split()[7] + break + try: + meassured_reflections = int(all_reflections) - int(missing_reflections) + except ValueError: + pass + return meassured_reflections + + def calculate_correlaton_between_intensities_in_mtzfiles(self, mtzin): + CC = "0.0" + errorMessage = "" + cmd = ( + "pointless hklin %s hklref %s << eof\n" % (mtzin, self.mtzfile) + + "labref I=IMEAN\n" + "labin I=IMEAN\n" + "eof\n" + ) + + pointless = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + foundLine = False + for line in iter(pointless.stdout.readline, ""): + if foundLine: + CC = line.split()[3] + break + if "Alternative reindexing Lklhd CC" in line: + foundLine = True + if "**** Incompatible symmetries ****" in line: + errorMessage = "**** Incompatible symmetries ****" + break + if ( + "Merged test dataset (HKLIN)" + " has different Laue symmetry to reference set" in line + ): + errorMessage = "%s has different Laue symmetry to %s" % ( + mtzin, + self.mtzfile, + ) + break + + return CC, errorMessage + + def get_all_values_as_dict(self): + mtz = { + "resolution_high": "n/a", + "unitcell": "n/a", + "spacegroup": "n/a", + "unitcell_volume": "n/a", + "bravais_lattice": "n/a", + } + a = 0.0 + b = 0.0 + c = 0.0 + alpha_rad = 0.0 + beta_rad = 0.0 + gamma_rad = 0.0 + resolution_line = 1000000 + cell_line = 1000000 + mtzdmp = subprocess.Popen(["mtzdmp", self.mtzfile], stdout=subprocess.PIPE) + for n, line in enumerate(iter(mtzdmp.stdout.readline, "")): + if line.startswith(" * Resolution Range :"): + resolution_line = n + 2 + if n == resolution_line and len(line.split()) == 8: + mtz["resolution_high"] = round(float(line.split()[5]), 2) + if line.startswith(" * Cell Dimensions :"): + cell_line = n + 2 + if n == cell_line and len(line.split()) == 6: + a = round(float(line.split()[0]), 1) + b = round(float(line.split()[1]), 1) + c = round(float(line.split()[2]), 1) + alpha = round(float(line.split()[3]), 1) + beta = round(float(line.split()[4]), 1) + gamma = round(float(line.split()[5]), 1) + mtz["unitcell"] = ( + str(a) + + " " + + str(b) + + " " + + str(c) + + " " + + str(alpha) + + " " + + str(beta) + + " " + + str(gamma) + ) + alpha_rad = math.radians(alpha) + beta_rad = math.radians(beta) + gamma_rad = math.radians(gamma) + if line.startswith(" * Space group ="): + spg_number = int(line[line.rfind(")") - 3 : line.rfind(")")]) + mtz["bravais_lattice"] = self.get_bravais_lattice_from_spg_number( + spg_number + ) + mtz["spacegroup"] = line[line.find("'") + 1 : line.rfind("'")] + if mtz["bravais_lattice"] == "triclinic": + mtz["unitcell_volume"] = ( + a + * b + * c + * math.sqrt( + ( + 1 + - math.cos(alpha_rad) ** 2 + - math.cos(beta_rad) ** 2 + - math.cos(gamma_rad) ** 2 + ) + + 2 + * (math.cos(alpha_rad) * math.cos(beta_rad) * math.cos(gamma_rad)) + ) + ) + elif "monoclinic" in mtz["bravais_lattice"]: + mtz["unitcell_volume"] = round(a * b * c * math.sin(beta_rad), 1) + elif ( + mtz["bravais_lattice"] == "orthorhombic" + or mtz["bravais_lattice"] == "tetragonal" + or mtz["bravais_lattice"] == "cubic" + ): + mtz["unitcell_volume"] = round(a * b * c, 1) + elif ( + mtz["bravais_lattice"] == "hexagonal" + or mtz["bravais_lattice"] == "rhombohedral" + ): + mtz["unitcell_volume"] = round(a * b * c * (math.sin(math.radians(60))), 1) + + return mtz + + def get_all_columns_as_dict(self): + column_dict = {"F": [], "I": [], "SIG": [], "PHS": [], "FOM": [], "RFREE": []} + startline = 1000000 + mtzdmp = subprocess.Popen(["mtzdmp", self.mtzfile], stdout=subprocess.PIPE) + for n, line in enumerate(iter(mtzdmp.stdout.readline, "")): + if line.startswith(" Col Sort Min Max Num"): + startline = n + 2 + if n >= startline and len(line.split()) > 10: + if line.split()[10] == "F": + column_dict["F"].append(line.split()[11]) + if line.split()[10] == "J": + column_dict["I"].append(line.split()[11]) + if line.split()[10] == "Q": + column_dict["SIG"].append(line.split()[11]) + if line.split()[10] == "I": + column_dict["RFREE"].append(line.split()[11]) + if line.split()[10] == "P": + column_dict["PHS"].append(line.split()[11]) + if line.split()[10] == "W": + column_dict["FOM"].append(line.split()[11]) + + return column_dict + + def get_all_columns_as_list(self): + column_list = self.iotbxMTZ.column_labels() + return column_list + + +class external_software: + def __init__(self, xce_logfile): + self.available_programs = {} + self.Logfile = XChemLog.updateLog(xce_logfile) + + def log_found_status(self, program_name): + self.Logfile.insert( + "{0:50} {1:10}".format( + "checking for {}:".format(program_name), + "found" if self.available_programs[program_name] else "not found", + ) + ) + + def check(self): + self.Logfile.insert("Searching for external software...") + + self.available_programs["refmac5"] = find_executable("refmac5") is not None + self.log_found_status("refmac5") + + self.available_programs["phenix.molprobity"] = ( + find_executable("phenix.molprobity") is not None + ) + self.log_found_status("phenix.molprobity") + + self.available_programs["phenix.find_tls_groups"] = ( + find_executable("phenix.find_tls_groups") is not None + ) + self.log_found_status("phenix.find_tls_groups") + + self.available_programs["mmtbx.validate_ligands"] = ( + find_executable("mmtbx.validate_ligands") is not None + ) + self.log_found_status("mmtbx.validate_ligands") + + self.available_programs["acedrg"] = find_executable("acedrg") is not None + self.log_found_status("acedrg") + + self.available_programs["phenix.elbow"] = ( + find_executable("phenix.elbow") is not None + ) + self.log_found_status("phenix.elbow") + + self.available_programs["grade"] = find_executable("grade") is not None + self.log_found_status("grade") + + self.available_programs["giant.create_occupancy_params"] = ( + find_executable("giant.create_occupancy_params") is not None + ) + self.log_found_status("giant.create_occupancy_params") + + self.available_programs["mogul"] = ( + "BDG_TOOL_MOGUL" in os.environ + and find_executable(os.environ["BDG_TOOL_MOGUL"]) is not None + ) + self.log_found_status("mogul") + + self.available_programs["gemmi"] = find_executable("gemmi") is not None + self.log_found_status("gemmi") + + return self.available_programs + + +class pdbtools(object): + def __init__(self, pdb): + self.pdb = pdb + self.pdb_inp = iotbx.pdb.input(file_name=self.pdb) + self.hierarchy = self.pdb_inp.construct_hierarchy() + + self.AminoAcids = [ + "ALA", + "ARG", + "ASN", + "ASP", + "CYS", + "GLU", + "GLN", + "GLY", + "HIS", + "ILE", + "LEU", + "LYS", + "MET", + "PHE", + "PRO", + "SER", + "THR", + "TRP", + "TYR", + "VAL", + "CSO", + "HYP", + ] + self.Solvents = ["DMS", "EDO", "GOL", "HOH"] + self.Ions = ["NA", "MG", "CL", "K", "SO4", "PO4", "CA"] + self.xce_ligands = ["LIG", "DRG", "FRS"] + + self.space_group_dict = { + "triclinic": [1], + "monoclinic_P": [3, 4], + "monoclinic_C": [5], + "orthorhombic": [16, 17, 18, 19, 20, 21, 22, 23, 24], + "tetragonal": [ + 75, + 76, + 77, + 78, + 79, + 80, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + ], + "hexagonal": [ + 143, + 144, + 145, + 149, + 150, + 151, + 152, + 153, + 154, + 168, + 169, + 170, + 171, + 172, + 173, + 177, + 178, + 179, + 180, + 181, + 182, + ], + "rhombohedral": [146, 155], + "cubic": [195, 196, 197, 198, 199, 207, 208, 209, 210, 211, 212, 213, 214], + } + + self.point_group_dict = { + "1": [1], + "2": [3, 4, 5], + "222": [16, 17, 18, 19, 20, 21, 22, 23, 24], + "4": [75, 76, 77, 78, 79, 80], + "422": [89, 90, 91, 92, 93, 94, 95, 96, 97, 98], + "3": [143, 144, 145, 146], + "32": [149, 150, 151, 152, 153, 154, 155], + "6": [168, 169, 170, 171, 172, 173], + "622": [177, 178, 179, 180, 181, 182], + "23": [195, 196, 197, 198, 199], + "432": [207, 208, 209, 210, 211, 212, 213, 214], + } + + self.nr_asu_in_unitcell_for_point_group = { + "1": 1, + "2": 2, + "222": 4, + "4": 4, + "422": 8, + "3": 3, + "32": 6, + "6": 6, + "622": 12, + "23": 12, + "432": 24, + } + + def amino_acids(self): + return self.AminoAcids + + def get_refinement_program(self): + program = "unknown" + for remark in self.pdb_inp.remark_section(): + if "PROGRAM" in remark: + if "refmac" in remark.lower(): + program = "REFMAC" + elif "phenix" in remark.lower(): + program = "PHENIX" + elif "buster" in remark.lower(): + program = "BUSTER" + return program + + def get_residues_with_resname(self, resname): + ligands = [] + for model in self.hierarchy.models(): + for chain in model.chains(): + for conformer in chain.conformers(): + for residue in conformer.residues(): + if residue.resname == resname: + if [ + residue.resname, + residue.resseq, + chain.id, + ] not in ligands: + ligands.append( + [residue.resname, residue.resseq, chain.id] + ) + return ligands + + def save_residues_with_resname(self, outDir, resname): + ligands = self.get_residues_with_resname(resname) + ligList = [] + for ligand in ligands: + sel_cache = self.hierarchy.atom_selection_cache() + lig_sel = sel_cache.selection( + "(resname %s and resseq %s and chain %s)" + % (ligand[0], ligand[1], ligand[2]) + ) + hierarchy_lig = self.hierarchy.select(lig_sel) + ligName = (ligand[0] + "-" + ligand[2] + "-" + ligand[1] + ".pdb").replace( + " ", "" + ) + ligList.append(ligName) + + try: + f = open(os.path.join(outDir, ligName), "w") + f.write( + hierarchy_lig.as_pdb_string( + crystal_symmetry=self.pdb_inp.crystal_symmetry() + ) + ) + f.close() + except IOError: + print("ERROR: {0!s} exists; skipping...") + + return ligList + + def GetProteinChains(self): + chain = [] + for line in open(self.pdb): + if line.startswith("ATOM"): + if line[17:20] in self.AminoAcids: + if line[21:22] not in chain: + chain.append(line[21:22]) + return chain + + def get_bravais_lattice_from_spg_number(self, number): + lattice = "" + for bravaislattice in self.space_group_dict: + for spg_number in self.space_group_dict[bravaislattice]: + if str(spg_number) == str(number): + lattice = bravaislattice + return lattice + + def find_ligands(self): + Ligands = [] + for line in open(self.pdb): + if (line.startswith("ATOM") or line.startswith("HETATM")) and line[ + 17:20 + ].replace(" ", "") not in self.AminoAcids + self.Solvents + self.Ions: + if [line[17:20], line[21:22], line[23:26]] not in Ligands: + Ligands.append([line[17:20], line[21:22], line[23:26]]) + return Ligands + + def save_ligands_to_pdb(self): + Ligands = self.find_ligands() + if not Ligands == []: + for n, item in enumerate(Ligands): + pdb = "" + for line in open(self.pdb): + if line.startswith("CRYST"): + pdb += line + if ( + (line.startswith("ATOM") or line.startswith("HETATM")) + and line[17:20] == item[0] + and line[21:22] == item[1] + and line[23:26] == item[2] + ): + pdb = pdb + line + f = open("ligand_{0!s}.pdb".format(n), "w") + f.write(pdb) + f.close() + return Ligands + + def find_xce_ligand_details(self): + Ligands = [] + for line in open(self.pdb): + if line.startswith("ATOM") or line.startswith("HETATM"): + resname = str(line[17:20]).replace(" ", "") + if resname in self.xce_ligands: + chainID = str(line[21:23]).replace(" ", "") + resseq = str(line[23:26]).replace(" ", "") + altLoc = str(line[16:17]).replace(" ", "") + if [resname, chainID, resseq, altLoc] not in Ligands: + Ligands.append([resname, chainID, resseq, altLoc]) + return Ligands + + def ligand_details_as_list(self): + Ligands = [] + for line in open(self.pdb): + if line.startswith("ATOM") or line.startswith("HETATM"): + resname = str(line[17:20]).replace(" ", "") + if resname in self.xce_ligands: + chainID = str(line[21:23]).replace(" ", "") + resseq = str(line[23:26]).replace(" ", "") + altLoc = str(line[16:17]).replace(" ", "") + occupancy = str(line[56:60]).replace(" ", "") + if [resname, chainID, resseq, altLoc, occupancy] not in Ligands: + Ligands.append([resname, chainID, resseq, altLoc, occupancy]) + return Ligands + + def get_center_of_gravity_of_residue_ish(self, chain, number): + print("-> chain:", chain) + print("-> number:", number) + X = 0.0 + Y = 0.0 + Z = 0.0 + x_list = [] + y_list = [] + z_list = [] + # pdb definition see: + # http://www.wwpdb.org/documentation/file-format-content/format33/sect9.html#ATOM + for line in open(self.pdb): + if ( + (line.startswith("ATOM") or line.startswith("HETATM")) + and line[21:22].replace(" ", "") == chain.replace(" ", "") + and line[22:26].replace(" ", "") == str(number).replace(" ", "") + ): + X = float(line[30:38]) + x_list.append(X) + Y = float(line[38:46]) + y_list.append(Y) + Z = float(line[46:54]) + z_list.append(Z) + # 'ish' because it's not really the centre of gravity + # but the the middle of the min/max of each x,y,z + X = ((max(x_list) - min(x_list)) / 2) + min(x_list) + Y = ((max(y_list) - min(y_list)) / 2) + min(y_list) + Z = ((max(z_list) - min(z_list)) / 2) + min(z_list) + return X, Y, Z + + def get_center_of_gravity_of_molecule_ish(self): + X = 0.0 + Y = 0.0 + Z = 0.0 + x_list = [] + y_list = [] + z_list = [] + # pdb definition see: + # http://www.wwpdb.org/documentation/file-format-content/format33/sect9.html#ATOM + for line in open(self.pdb): + if line.startswith("ATOM") or line.startswith("HETATM"): + X = float(line[30:38]) + x_list.append(X) + Y = float(line[38:46]) + y_list.append(Y) + Z = float(line[46:54]) + z_list.append(Z) + # 'ish' because it's not really the centre of gravity + # but the the middle of the min/max of each x,y,z + X = ((max(x_list) - min(x_list)) / 2) + min(x_list) + Y = ((max(y_list) - min(y_list)) / 2) + min(y_list) + Z = ((max(z_list) - min(z_list)) / 2) + min(z_list) + return X, Y, Z + + def ElementDict(self, resname, chainID, resseq, altLoc): + ElementDict = { + "C": 0, + "N": 0, + "O": 0, + "P": 0, + "S": 0, + "BR": 0, + "CL": 0, + "I": 0, + "F": 0, + } + + for line in open(self.pdb): + if line.startswith("ATOM") or line.startswith("HETATM"): + resname_line = str(line[17:20]).replace(" ", "") + chainID_line = str(line[21:23]).replace(" ", "") + resseq_line = str(line[23:26]).replace(" ", "") + altLoc_line = str(line[16:17]).replace(" ", "") + element_line = str(line[66:78]).replace(" ", "") + if ( + resname_line == resname + and chainID_line == chainID + and resseq_line == resseq + and altLoc_line == altLoc + ): + if element_line.upper() in ElementDict: + ElementDict[element_line.upper()] += 1 + + return ElementDict + + +class logtools: + def __init__(self, logfile): + self.logfile = logfile + + def phenix_molprobity(self): + QualityIndicators = { + "MolprobityScore": "n/a", + "MolprobityScoreColor": "gray", + "RamachandranOutliers": "n/a", + "RamachandranOutliersColor": "gray", + "RamachandranFavored": "n/a", + "RamachandranFavoredColor": "gray", + } + + # Molprobity = validation_summary.txt + if os.path.isfile(self.logfile): + for line in open(self.logfile): + if "molprobity score" in line.lower(): + if len(line.split()) >= 4: + QualityIndicators["MolprobityScore"] = line.split()[3] + try: + if float(line.split()[3]) < 2: + QualityIndicators["MolprobityScoreColor"] = "green" + if 2 <= float(line.split()[3]) < 3: + QualityIndicators["MolprobityScoreColor"] = "orange" + if float(line.split()[3]) >= 3: + QualityIndicators["MolprobityScoreColor"] = "red" + except ValueError: + pass + if "ramachandran outliers" in line.lower(): + if len(line.split()) >= 4: + QualityIndicators["RamachandranOutliers"] = line.split()[3] + try: + if float(line.split()[3]) < 0.3: + QualityIndicators["RamachandranOutliersColor"] = "green" + if 0.3 <= float(line.split()[3]) < 1: + QualityIndicators[ + "RamachandranOutliersColor" + ] = "orange" + if float(line.split()[3]) >= 1: + QualityIndicators["RamachandranOutliersColor"] = "red" + except ValueError: + pass + if "favored" in line.lower(): + if len(line.split()) == 4: + QualityIndicators["RamachandranFavored"] = line.split()[2] + try: + if float(line.split()[2]) < 90: + QualityIndicators["RamachandranFavoredColor"] = "red" + if 90 <= float(line.split()[2]) < 98: + QualityIndicators["RamachandranFavoredColor"] = "orange" + if float(line.split()[2]) >= 98: + QualityIndicators["RamachandranFavoredColor"] = "green" + except ValueError: + pass + + return QualityIndicators + + def refmac_log(self): + QualityIndicators = {"MatrixWeight": "n/a"} + + # Matrix Weight + if os.path.isfile(self.logfile): + for line in open(self.logfile): + if line.startswith(" Weight matrix") and len(line.split()) == 3: + QualityIndicators["MatrixWeight"] = line.split()[2] + + return QualityIndicators + + +def calculate_distance_between_coordinates(x1, y1, z1, x2, y2, z2): + distance = 0.0 + distance = math.sqrt( + math.pow(float(x1) - float(x2), 2) + + math.pow(float(y1) - float(y2), 2) + + math.pow(float(z1) - float(z2), 2) + ) + return distance + + +class smilestools(object): + def __init__(self, smiles): + self.smiles = smiles + + def ElementDict(self): + ElementDict = { + "C": 0, + "N": 0, + "O": 0, + "P": 0, + "S": 0, + "BR": 0, + "CL": 0, + "I": 0, + "F": 0, + } + + m = Chem.MolFromSmiles(self.smiles) + for atom in m.GetAtoms(): + if str(atom.GetSymbol()).upper() in ElementDict: + ElementDict[str(atom.GetSymbol()).upper()] += 1 + + return ElementDict + + +class maptools(object): + def calculate_map(self, mtz, F, PH): + cmd = ( + "fft hklin %s mapout %s << EOF\n" % (mtz, mtz.replace(".mtz", ".ccp4")) + + "labin F1=%s PHI=%s\n" % (F, PH) + + "EOF\n" + ) + os.system(cmd) + + def cut_map_around_ligand(self, map, ligPDB, border): + if map.endswith(".map"): + map_extension = ".map" + elif map.endswith(".ccp4"): + map_extension = ".ccp4" + else: + map_extension = "" + + cmd = ( + "mapmask mapin %s mapout %s xyzin %s << eof\n" + % (map, map.replace(map_extension, "_mapmask" + map_extension), ligPDB) + + " border %s\n" % border + + " end\n" + "eof" + ) + os.system(cmd) + + +class mtztools_gemmi: + def __init__(self, mtz): + self.mtz = gemmi.read_mtz_file(mtz) + + def get_map_labels(self): + labelList = [] + for column in self.mtz.columns: + labelList.append(column.label) + FWT = None + PHWT = None + DELFWT = None + PHDELWT = None + + if "FWT" in labelList and "PHWT" in labelList: + FWT = "FWT" + PHWT = "PHWT" + + if "DELFWT" in labelList and "PHDELWT" in labelList: + DELFWT = "DELFWT" + PHDELWT = "PHDELWT" + + if "2FOFCWT" in labelList and "PH2FOFCWT" in labelList: + FWT = "2FOFCWT" + PHWT = "PH2FOFCWT" + + if "FOFCWT" in labelList and "PHFOFCWT" in labelList: + DELFWT = "FOFCWT" + PHDELWT = "PHFOFCWT" + + return FWT, PHWT, DELFWT, PHDELWT + + def get_high_low_resolution_limits(self): + resl = self.mtz.resolution_low() + resh = self.mtz.resolution_high() + return resh, resl + + +class maptools_gemmi: + def __init__(self, emap): + self.emap = emap + self.emtz = emap.replace(".ccp4", ".mtz").replace(".map", ".mtz") + + def map_to_sf(self, resolution): + if os.path.isfile(self.emtz): + print("mtz file of event map exists; skipping...") + return + cmd = "gemmi map2sf %s %s FWT PHWT --dmin=%s" % ( + self.emap, + self.emtz, + resolution, + ) + print(("converting map with command:\n" + cmd)) + os.system(cmd) + if os.path.isfile(self.emtz): + print("event map to SF conversion successful") + mtz = gemmi.read_mtz_file(self.emtz) + mtz.history += ["date created: " + time.ctime(os.path.getmtime(self.emap))] + mtz.history += ["folder: " + os.getcwd()] + mtz.history += ["file name: " + self.emap] + if "BDC" in self.emap: + mtz.history += [ + "BDC value: " + + self.emap[ + self.emap.find("BDC") + + 4 : self.emap.find("BDC") + + 4 + + self.emap[self.emap.find("BDC") + 4 :].find("_") + ] + ] + else: + print("failed to convert event map to SF") + + +class pdbtools_gemmi: + def __init__(self, pdb): + self.pdb = gemmi.read_structure(pdb) + + def get_ligand_models_as_dict(self, ligandID): + ligandDict = {} + for model in self.pdb: + for chain in model: + for residue in chain: + if residue.name == ligandID: + if ( + str( + residue.name + + "-" + + chain.name + + "-" + + str(residue.seqid.num) + ) + not in ligandDict + ): + ligandDict[ + str( + residue.name + + "-" + + chain.name + + "-" + + str(residue.seqid.num) + ) + ] = None + m = gemmi.Model("1") + m.add_chain(gemmi.Chain("X")) + c = m["X"].get_polymer() + c.add_residue(gemmi.Residue(), 0) + c[0].name = residue.name + for n, atom in enumerate(residue): + c[0].add_atom(atom, n) + ligandDict[ + str( + residue.name + + "-" + + chain.name + + "-" + + str(residue.seqid.num) + ) + ] = m + return ligandDict + + def center_of_mass_ligand_dict(self, ligandID): + ligandDict = self.get_ligand_models_as_dict(ligandID) + ligandPositionDict = {} + for ligand in ligandDict: + pos = ligandDict[ligand].calculate_center_of_mass() + ligandPositionDict[ligand] = [pos.x, pos.y, pos.z] + return ligandPositionDict + + def save_ligands_to_pdb(self, ligandID): + ligandDict = self.get_ligand_models_as_dict(ligandID) + for ligand in ligandDict: + s = gemmi.Structure() + s.add_model(ligandDict[ligand]) + s.write_pdb(ligand + ".pdb") diff --git a/xce/lib/__init__.py b/xce/lib/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/xce/lib/cluster/__init__.py b/xce/lib/cluster/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/xce/lib/cluster/slurm.py b/xce/lib/cluster/slurm.py new file mode 100755 index 00000000..8de9b612 --- /dev/null +++ b/xce/lib/cluster/slurm.py @@ -0,0 +1,164 @@ +import os +import ssl +import json +import httplib +import paramiko +import time +import traceback +import gtk +from PyQt4 import QtGui +from datetime import datetime +from xce.lib.XChemLog import updateLog +from uuid import uuid4 + +CLUSTER_BASTION = "wilson.diamond.ac.uk" +CLUSTER_USER = os.environ.get("CLUSTER_USER", os.getlogin()) +CLUSTER_HOST = "slurm-rest.diamond.ac.uk" +CLUSTER_PORT = 8443 +CLUSTER_PARTITION = "cs05r" + +TOKEN = None +TOKEN_EXPIRY = None + +POPUP_TITLE = "SLURM Authentication" + + +def fetch_password_qt(password_prompt): + password, ok = QtGui.QInputDialog.getText( + None, POPUP_TITLE, password_prompt, mode=QtGui.QLineEdit.Password + ) + return password if ok else None + + +def fetch_password_gtk(password_prompt): + dialog = gtk.MessageDialog( + None, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_QUESTION, + gtk.BUTTONS_OK_CANCEL, + None, + ) + dialog.set_title(POPUP_TITLE) + dialog.set_markup(password_prompt) + + entry = gtk.Entry() + entry.set_visibility(False) + dialog.vbox.pack_end(entry) + dialog.show_all() + + dialog.run() + password = entry.get_text() + dialog.destroy() + return password + + +def get_token(fetch_password, error=None): + global TOKEN + global TOKEN_EXPIRY + + if TOKEN is None or TOKEN_EXPIRY is None or TOKEN_EXPIRY < time.time() + 60: + password_prompt = error + "\n" + "Password:" if error else "Password:" + password = fetch_password(password_prompt) + if password is None: + return None + + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.load_system_host_keys() + try: + ssh.connect(CLUSTER_BASTION, username=CLUSTER_USER, password=str(password)) + except paramiko.AuthenticationException: + print(traceback.format_exc()) + return get_token(fetch_password, error="SSH Authentication Failed") + stdin, stdout, stderr = ssh.exec_command("scontrol token lifespan=3600") + if stdout.channel.recv_exit_status() != 0: + return get_token(fetch_password, error="Token Acquisition Failed") + final_line = stdout.next() + for final_line in stdout: + continue + TOKEN = final_line.split("=")[1].strip() + TOKEN_EXPIRY = time.time() + 3600 + return TOKEN + + +def construct_headers(token): + return { + "Content-Type": "application/json", + "X-SLURM-USER-NAME": CLUSTER_USER, + "X-SLURM-USER-TOKEN": token, + } + + +def submit_cluster_job( + name, file, xce_logfile, token, array=None, exclusive=False, memory=None, tasks=None +): + with open(file) as script_file: + script = "\n".join(script_file.readlines()) + payload = dict( + script=script, + job=dict( + partition=CLUSTER_PARTITION, + name=str(name), + account=CLUSTER_USER, + current_working_directory=os.getcwd(), + environment=[ + "USER={}".format(os.environ["USER"]), + "XChemExplorer_DIR={}".format(os.environ["XChemExplorer_DIR"]), + ], + standard_output=os.path.join(os.getcwd(), "{}.stdout".format(name)), + standard_error=os.path.join(os.getcwd(), "{}.stderr".format(name)), + ), + ) + if array is not None: + payload["job"]["array"] = array + if exclusive is True: + payload["job"]["exclusive"] = "mcs" + payload["job"]["mcs_label"] = str(uuid4()) + if memory is not None: + payload["job"]["memory_per_node"] = dict() + payload["job"]["memory_per_node"]["set"] = True + payload["job"]["memory_per_node"]["number"] = memory + if tasks is not None: + payload["job"]["tasks_per_node"] = tasks + body = json.dumps(payload) + logfile = updateLog(xce_logfile) + logfile.insert("Submitting job, '{}', to Slurm with body: {}".format(name, body)) + connection = httplib.HTTPSConnection( + CLUSTER_HOST, CLUSTER_PORT, context=ssl._create_unverified_context() + ) + connection.request( + "POST", "/slurm/v0.0.40/job/submit", body=body, headers=construct_headers(token) + ) + response = connection.getresponse().read() + logfile.insert("Got response: {}".format(response)) + + +def query_running_jobs(xce_logfile, token): + connection = httplib.HTTPSConnection( + CLUSTER_HOST, + CLUSTER_PORT, + context=ssl._create_unverified_context(), + ) + connection.request("GET", "/slurm/v0.0.40/jobs", headers=construct_headers(token)) + response = connection.getresponse() + response_body = response.read() + + if response.status != 200: + logifle = updateLog(xce_logfile) + logifle.insert("Got response: {}".format(response_body)) + + jobs = [] + for job in json.loads(response_body)["jobs"]: + if job["user_name"] != CLUSTER_USER: + continue + + job_id = job["job_id"] + job_name = job["name"] + job_status = job["job_state"] + + start_time = datetime.utcfromtimestamp(job["start_time"]) + run_time = datetime.now() - start_time + + jobs.append((job_id, job_name, job_status, run_time)) + + return jobs diff --git a/xce/lib/coot_utils_XChem.py b/xce/lib/coot_utils_XChem.py new file mode 100755 index 00000000..66f56eef --- /dev/null +++ b/xce/lib/coot_utils_XChem.py @@ -0,0 +1,99 @@ +import coot + + +# return a list of molecule numbers (closed and open) +# The elements of the returned list need to be tested against +# is_valid_model_molecule_qm +# +def molecule_number_list(): + ret = [] + for mol_no in range(coot.graphics_n_molecules()): + if valid_map_molecule_qm(mol_no) or valid_model_molecule_qm(mol_no): + ret.append(mol_no) + return ret + + +# The screen centre. +# +# return the rotation centre as a 3 membered list of numbers +# is python list [...] !!! +# + + +def rotation_centre(): + return [ + coot.rotation_centre_position(0), + coot.rotation_centre_position(1), + coot.rotation_centre_position(2), + ] + + +# Return the molecule centre as a list of 3 numbers. +# +# Note: mol_cen could contain values less than -9999. +# + + +def molecule_centre(imol): + return [ + coot.molecule_centre_internal(imol, 0), + coot.molecule_centre_internal(imol, 1), + coot.molecule_centre_internal(imol, 2), + ] + + +# Move the centre of molecule number imol to the current screen centre +# + + +def move_molecule_to_screen_centre(imol): + if valid_model_molecule_qm(imol): + rotate_centre = rotation_centre() + coot.translate_molecule_by( + imol, + (rotate_centre[0] - molecule_centre(imol)[0]), + (rotate_centre[1] - molecule_centre(imol)[1]), + (rotate_centre[2] - molecule_centre(imol)[2]), + ) + + +# This is a short name for the above. +# deftexi move_molecule_here +move_molecule_here = move_molecule_to_screen_centre + + +# return a list of chain ids for given molecule number @var{imol}. +# return empty list on error +# + + +def chain_ids(imol): + chain_id_is = [] + number_of_chains = coot.n_chains(imol) + for chain_no in range(number_of_chains): + chain_id_is.append(coot.chain_id_py(imol, chain_no)) + return chain_id_is + + +# python (schemeyish) interface to eponymous scripting interface function!? +# return True or False +# + + +def valid_model_molecule_qm(imol): + if coot.is_valid_model_molecule(imol) == 1: + return True + else: + return False + + +# python (schemeyish) interface to eponymous scripting interface function. +# return True or False +# + + +def valid_map_molecule_qm(imol): + if coot.is_valid_map_molecule(imol) == 1: + return True + else: + return False diff --git a/xce/lib/html_fragments/download.html b/xce/lib/html_fragments/download.html new file mode 100755 index 00000000..66222302 --- /dev/null +++ b/xce/lib/html_fragments/download.html @@ -0,0 +1,32 @@ +
+

%s - XChem results

+ +
+

+

Click event map in table to view a different crystal / compound pair (press SHIFT and + scroll mouse wheel to change contour level of event map)

+ +
\ No newline at end of file diff --git a/xce/lib/html_fragments/footer.html b/xce/lib/html_fragments/footer.html new file mode 100755 index 00000000..5a752aeb --- /dev/null +++ b/xce/lib/html_fragments/footer.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/xce/lib/html_fragments/guide.html b/xce/lib/html_fragments/guide.html new file mode 100755 index 00000000..8199ee96 --- /dev/null +++ b/xce/lib/html_fragments/guide.html @@ -0,0 +1,35 @@ + +
+

Ligand-bound models for Summary

+

Interpreting 'Ligand confidence'

+

4 - High Confidence: The expected ligand was easily interpretable from clear density, and subsequent + refinement was well-behaved. This ligand can be trusted. +
3 - Clear density, unexpected ligand: Density very clearly showed a well-defined ligand, but that + ligand was unexpected in that crystal/dataset. The observed ligand was modelled anyway, because its presence + could be explained in some way. +
2 - Correct ligand, weak density: Though density was weak, it was possible to model the expected + ligand, possibly including other circumstantial evidence (e.g. similar ligand in another model). +
1 - Low Confidence: The ligand model is to be treated with scepticism, because the evidence (density, + identity, pose) were not convincing. +

Interpreting 'Model status':

+

6 - Deposited: The model has been deposited in the PDB. +
5 - Deposition ready: The model is fully error-free, in every residue, and is ready for deposition. +
4 - CompChem ready: The model is complete and correct in the region of the bound ligand. There may be + remaining small errors elsewhere in the structure, but they are far away and unlikely to be relevant to any + computational analysis or compound design. +

Interpreting 'Ligand validation' spider plots:

Each axis represents one of the values described below; + small is better, and large values on any axis implies that further investigation is warranted. +

Quality (RSCC) reflects the fit of the atoms to the experimental density, and should typically be greater + than 0.7. +
Accuracy (RSZD) measures the amount of difference density that is found around these atoms, and + should be below 3. +
B-factor ratio measures the consistency of the model with surrounding protein, and is calculated from + the B factors of respectively the changed atoms and all side-chain atoms within 4Å. Large values (>3) + reflect poor evidence for the model, and intermediate values (1.5+) indicate errors in refinement or modelling; + for weakly-binding ligands, systematically large ratios may be justifiable. +
RMSD compares the positions of all atoms built into event density, with their positions after final + refinement, and should be below 1Å. +
Precision (RSZO/OCC) measures how clear the density is after refinement. (This is not a quality + indicator, but is related to strength of binding but not in a straightforward way.) +

+

\ No newline at end of file diff --git a/xce/lib/html_fragments/header.html b/xce/lib/html_fragments/header.html new file mode 100755 index 00000000..0a7eaef2 --- /dev/null +++ b/xce/lib/html_fragments/header.html @@ -0,0 +1,38 @@ + + + + + + + + Summary Fragment Hits + + + + + \ No newline at end of file diff --git a/xce/lib/html_fragments/ngl.html b/xce/lib/html_fragments/ngl.html new file mode 100755 index 00000000..e41aef97 --- /dev/null +++ b/xce/lib/html_fragments/ngl.html @@ -0,0 +1,286 @@ + + \ No newline at end of file diff --git a/xce/lib/html_fragments/table_header.html b/xce/lib/html_fragments/table_header.html new file mode 100755 index 00000000..87d13c4b --- /dev/null +++ b/xce/lib/html_fragments/table_header.html @@ -0,0 +1,19 @@ +\n" + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xce/lib/html_fragments/table_row.html b/xce/lib/html_fragments/table_row.html new file mode 100755 index 00000000..e01b6f86 --- /dev/null +++ b/xce/lib/html_fragments/table_row.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/xce/web/XChemWeb.py b/xce/web/XChemWeb.py new file mode 100755 index 00000000..17a939ce --- /dev/null +++ b/xce/web/XChemWeb.py @@ -0,0 +1,435 @@ +import os + +from xce.lib import XChemDB, XChemLog, XChemMain, XChemUtils + + +class export_to_html: + def __init__(self, htmlDir, projectDir, database, xce_logfile): + self.htmlDir = htmlDir + self.projectDir = projectDir + self.Logfile = XChemLog.updateLog(xce_logfile) + self.db = XChemDB.data_source(database) + self.db_dict = None + self.pdb = None + self.protein_name = None + + def prepare(self, whichSamples): + self.Logfile.insert("======== preparing HTML summary ========") + self.makeFolders() + self.copy_jscss() + html = XChemMain.html_header() + firstFile = True + for xtal in self.db.samples_for_html_summary(whichSamples): + self.db_dict = self.db.get_db_dict_for_sample(xtal) + if firstFile: + if self.db_dict["ProteinName"] == "None": + self.Logfile.warning("could not determine protein name") + try: + self.protein_name = xtal.split("-")[0] + self.Logfile.warning( + "xtal name = %s => setting protein name to %s" + % (xtal, self.protein_name) + ) + except IndexError: + self.Logfile.warning( + "could not determine protein name from cystal name;" + " setting to None" + ) + self.protein_name = "" + else: + self.protein_name = self.db_dict["ProteinName"] + self.Logfile.insert("protein name is: " + self.protein_name) + self.copy_pdb(xtal) + self.copy_mtz(xtal) + self.copy_ligand_files(xtal) + os.chdir(os.path.join(self.projectDir, xtal)) + ligandDict = XChemUtils.pdbtools_gemmi( + "refine.pdb" + ).center_of_mass_ligand_dict("LIG") + self.Logfile.insert( + xtal + ": saving ligand(s) of type LIG in refine.pdb as PDB files..." + ) + XChemUtils.pdbtools_gemmi("refine.pdb").save_ligands_to_pdb("LIG") + for ligand in ligandDict: + self.Logfile.insert(xtal + ": current ligand -> " + ligand) + os.chdir(os.path.join(self.projectDir, xtal)) + ligName = ligand.split("-")[0] + ligChain = ligand.split("-")[1] + ligNumber = ligand.split("-")[2] + eventMap = "" + if os.path.isfile(xtal + "_" + ligand + "_event.ccp4"): + eventMap = xtal + "_" + ligand + "_event.ccp4" + x = ligandDict[ligand][0] + y = ligandDict[ligand][1] + z = ligandDict[ligand][2] + self.copy_spider_plot(xtal, ligand) + pdbID = self.db_dict["Deposition_PDB_ID"] + compoundImage = xtal + "_" + self.db_dict["CompoundCode"] + ".png" + compoundCIF = xtal + "_" + self.db_dict["CompoundCode"] + ".cif" + residuePlot = xtal + "_" + ligand + ".png" + pdb = xtal + ".pdb" + event = xtal + "_" + ligand + "_event.ccp4" + thumbNail = xtal + "_" + ligand + "_thumb.png" + resoHigh = self.db_dict["DataProcessingResolutionHigh"] + spg = self.db_dict["RefinementSpaceGroup"] + unitCell = self.db_dict["DataProcessingUnitCell"] + t = "" + for ax in unitCell.split(): + t += str(round(float(ax), 1)) + " " + unitCell = t[:-1] + os.chdir(os.path.join(self.projectDir, xtal)) + if os.path.isfile("refine.mtz"): + self.Logfile.insert("%s: found refine.mtz" % xtal) + FWTmap, DELFWTmap = self.prepare_e_density_maps(xtal, ligand) + self.copy_electron_density(xtal, ligand, eventMap) + ligConfidence = self.db.get_ligand_confidence_for_ligand( + xtal, ligChain, ligNumber, ligName + ) + if ligConfidence.startswith("0"): + self.Logfile.warning( + "%s: ligand confidence of %s-%s-%s is %s; ignoring..." + % (xtal, ligChain, ligNumber, ligName, ligConfidence) + ) + self.Logfile.warning( + "%s: this seems unlikely because this structure is apparently" + " ready for deposition" % xtal + ) + self.Logfile.warning( + '%s: will set it to "not assigned" for now, but please update' + " in soakDB" % xtal + ) + ligConfidence = "not assigned" + modelStatus = self.db_dict["RefinementOutcome"] + if firstFile: + html += XChemMain.html_ngl( + pdb, + eventMap.replace(self.projectDir, ""), + FWTmap, + DELFWTmap, + ligand, + ) + html += XChemMain.html_download(self.protein_name) + html += XChemMain.html_guide() + html += XChemMain.html_table_header() + firstFile = False + + html += XChemMain.html_table_row( + xtal, + pdbID, + ligand, + compoundImage, + residuePlot, + pdb, + event, + thumbNail, + resoHigh, + spg, + unitCell, + FWTmap, + DELFWTmap, + ligConfidence, + modelStatus, + ) + self.make_thumbnail(xtal, x, y, z, ligand, eventMap) + self.prepare_for_download(xtal, pdb, event, compoundCIF, ligand) + self.prepare_zip_archives() + self.write_html_file(html) + self.Logfile.insert("======== finished preparing HTML summary ========") + + def prepare_e_density_maps(self, xtal, ligand): + FWT, PHWT, DELFWT, PHDELWT = XChemUtils.mtztools_gemmi( + "refine.mtz" + ).get_map_labels() + self.Logfile.insert(xtal + ": calculating 2fofc map...") + XChemUtils.maptools().calculate_map("refine.mtz", FWT, PHWT) + if os.path.isfile("refine.ccp4"): + self.Logfile.insert(xtal + ": 2fofc map successfully calculated") + else: + self.Logfile.error(xtal + ": 2fofc map could not be calculated") + self.Logfile.insert(xtal + ": cutting 2fofc map 7A around " + ligand) + XChemUtils.maptools().cut_map_around_ligand("refine.ccp4", ligand + ".pdb", "7") + if os.path.isfile("refine_mapmask.ccp4"): + self.Logfile.insert( + xtal + ": 2fofc map around " + ligand + " successfully created" + ) + else: + self.Logfile.error( + xtal + ": 2fofc map around " + ligand + " could not be created" + ) + os.system("/bin/mv %s %s_%s_2fofc.ccp4" % ("refine_mapmask.ccp4", xtal, ligand)) + FWTmap = xtal + "_" + ligand + "_2fofc.ccp4" + self.Logfile.insert( + xtal + ": current 2fofc map -> " + xtal + "_" + ligand + "_2fofc.ccp4" + ) + XChemUtils.maptools().calculate_map("refine.mtz", DELFWT, PHDELWT) + XChemUtils.maptools().cut_map_around_ligand("refine.ccp4", ligand + ".pdb", "7") + os.system("/bin/mv %s %s_%s_fofc.ccp4" % ("refine_mapmask.ccp4", xtal, ligand)) + DELFWTmap = xtal + "_" + ligand + "_fofc.ccp4" + return FWTmap, DELFWTmap + + def prepare_zip_archives(self): + os.chdir(os.path.join(self.htmlDir, "files")) + self.Logfile.insert( + "%s: preparing ZIP archive of all PDB files" % self.protein_name + ) + os.system("zip %s_allPDBs.zip *.pdb" % self.protein_name) + self.Logfile.insert( + "%s: preparing ZIP archive of all PanDDA event maps" % self.protein_name + ) + os.system("zip %s_allEVENTmaps.zip *event.ccp4" % self.protein_name) + self.Logfile.insert( + "%s: preparing ZIP archive of all CIF files" % self.protein_name + ) + os.system("zip %s_allCIFs.zip *.cif" % self.protein_name) + self.Logfile.insert( + "%s: preparing ZIP archive of all MTZ files" % self.protein_name + ) + os.system("zip %s_allMTZs.zip *.mtz" % self.protein_name) + + def prepare_for_download(self, xtal, pdb, event, compoundCIF, ligID): + os.chdir(os.path.join(self.htmlDir, "tmp")) + self.Logfile.insert("%s: preparing files for download" % xtal) + zip_in = "" + + if os.path.isfile("../files/%s" % pdb): + os.system("/bin/cp ../files/%s ." % pdb) + zip_in += pdb + " " + else: + self.Logfile.error("%s: cannot find %s" % (xtal, pdb)) + + if os.path.isfile("../files/%s" % event): + os.system("/bin/cp ../files/%s ." % event) + zip_in += event + " " + else: + self.Logfile.error("%s: cannot find %s" % (xtal, event)) + + if os.path.isfile("../files/%s" % compoundCIF): + os.system("/bin/cp ../files/%s ." % compoundCIF) + zip_in += compoundCIF + " " + else: + self.Logfile.error("%s: cannot find %s" % (xtal, compoundCIF)) + + if zip_in != "": + self.Logfile.insert( + "%s: preparing zip file -> zip %s_%s.zip %s" + % (xtal, xtal, ligID, zip_in) + ) + os.system("zip %s_%s.zip %s" % (xtal, ligID, zip_in)) + os.system("/bin/mv %s_%s.zip ../download" % (xtal, ligID)) + os.system("/bin/rm -f *") + else: + self.Logfile.error( + "%s: cannot find any input files for creating of zip archive of %s_%s" + % (xtal, xtal, ligID) + ) + + def copy_jscss(self): + os.chdir(self.htmlDir) + self.Logfile.insert("copying css and js files to " + self.htmlDir) + os.system("/bin/cp -r %s/web/jscss/css ." % os.getenv("XChemExplorer_DIR")) + os.system("/bin/cp -r %s/web/jscss/js ." % os.getenv("XChemExplorer_DIR")) + + def make_thumbnail(self, xtal, x, y, z, ligID, eventMap): + self.Logfile.insert( + "%s: making thumbnail of for %s and %s" % (xtal, ligID, eventMap) + ) + sampleDir = os.path.join(self.projectDir, xtal) + os.chdir(sampleDir) + if not os.path.isfile("%s_%s_thumb.png" % (xtal, ligID)): + self.Logfile.insert("%s: preparing thumbnail image of %s" % (xtal, ligID)) + XChemMain.coot_prepare_input(x, y, z, ligID, sampleDir, eventMap) + XChemMain.coot_write_raster_file(ligID, sampleDir) + XChemMain.render_scene(xtal, ligID, sampleDir) + XChemMain.make_thumbnail(xtal, ligID, sampleDir) + if os.path.isfile("%s_%s_thumb.png" % (xtal, ligID)): + self.Logfile.insert( + "%s: managed to prepare %s_%s_thumb.png" % (xtal, xtal, ligID) + ) + self.copy_thumbnail(xtal, sampleDir, ligID) + else: + self.Logfile.error( + "%s: could not generate %s_%s_thumb.png" % (xtal, xtal, ligID) + ) + + def copy_thumbnail(self, xtal, sampleDir, ligID): + os.chdir(os.path.join(self.htmlDir, "png")) + self.Logfile.insert( + "%s: copying %s_%s_thumb.png to html png" % (xtal, xtal, ligID) + ) + os.system("/bin/cp %s/%s_%s_thumb.png ." % (sampleDir, xtal, ligID)) + + def makeFolders(self): + self.Logfile.insert("preparing folders in html directory") + os.chdir(self.htmlDir) + if not os.path.isdir("tmp"): + os.mkdir("tmp") + if not os.path.isdir("png"): + os.mkdir("png") + if not os.path.isdir("files"): + os.mkdir("files") + if not os.path.isdir("download"): + os.mkdir("download") + + def copy_pdb(self, xtal): + os.chdir(os.path.join(self.htmlDir, "files")) + self.pdb = None + if os.path.isfile( + os.path.join(self.projectDir, xtal, "refine.split.bound-state.pdb") + ): + self.pdb = XChemUtils.pdbtools( + os.path.join(self.projectDir, xtal, "refine.split.bound-state.pdb") + ) + self.Logfile.insert( + "%s: copying refine.split.bound-state.pdb to html directory" % xtal + ) + os.system( + "/bin/cp %s/refine.split.bound-state.pdb %s.pdb" + % (os.path.join(self.projectDir, xtal), xtal) + ) + else: + self.Logfile.error("%s: cannot find refine.split.bound-state.pdb" % xtal) + + def copy_mtz(self, xtal): + os.chdir(os.path.join(self.htmlDir, "files")) + if os.path.isfile(os.path.join(self.projectDir, xtal, xtal + ".free.mtz")): + self.Logfile.insert( + "%s: copying %s.free.mtz to html directory" % (xtal, xtal) + ) + os.system( + "/bin/cp %s/%s.free.mtz ." % (os.path.join(self.projectDir, xtal), xtal) + ) + else: + self.Logfile.error("%s: cannot find %s.free.mtz" % (xtal, xtal)) + + def copy_electron_density(self, xtal, ligand, eventMap): + os.chdir(os.path.join(self.htmlDir, "files")) + + emap = xtal + "_" + ligand + "_2fofc.ccp4" + if os.path.isfile(os.path.join(self.projectDir, xtal, emap)): + self.Logfile.insert("%s: copying %s to html directory" % (xtal, emap)) + os.system( + "/bin/cp %s/%s %s" % (os.path.join(self.projectDir, xtal), emap, emap) + ) + else: + self.Logfile.error("%s: cannot find %s" % (xtal, emap)) + + emap = xtal + "_" + ligand + "_fofc.ccp4" + if os.path.isfile(os.path.join(self.projectDir, xtal, emap)): + self.Logfile.insert("%s: copying %s to html directory" % (xtal, emap)) + os.system( + "/bin/cp %s/%s %s" % (os.path.join(self.projectDir, xtal), emap, emap) + ) + else: + self.Logfile.error("%s: cannot find %s" % (xtal, emap)) + + self.Logfile.insert( + "%s: looking for %s" % (xtal, os.path.join(self.projectDir, xtal, eventMap)) + ) + if os.path.isfile(os.path.join(self.projectDir, xtal, eventMap)): + self.Logfile.insert("%s: copying %s to html directory" % (xtal, eventMap)) + os.system( + "/bin/cp %s/%s %s" + % (os.path.join(self.projectDir, xtal), eventMap, eventMap) + ) + else: + self.Logfile.error("%s: cannot find %s" % (xtal, eventMap)) + + def copy_ligand_files(self, xtal): + os.chdir(os.path.join(self.htmlDir, "files")) + + if os.path.isfile( + os.path.join(self.projectDir, xtal, self.db_dict["CompoundCode"] + ".cif") + ): + self.Logfile.insert("%s: copying compound cif file" % xtal) + os.system( + "/bin/cp %s %s_%s" + % ( + os.path.join( + self.projectDir, xtal, self.db_dict["CompoundCode"] + ".cif" + ), + xtal, + self.db_dict["CompoundCode"] + ".cif", + ) + ) + else: + self.Logfile.error( + "%s: cannot find compound cif file -> %s" + % (xtal, self.db_dict["CompoundCode"] + ".cif") + ) + + os.chdir(os.path.join(self.htmlDir, "png")) + + if os.path.isfile( + os.path.join(self.projectDir, xtal, self.db_dict["CompoundCode"] + ".png") + ): + self.Logfile.insert("%s: copying compound png file" % xtal) + os.system( + "/bin/cp %s %s_%s" + % ( + os.path.join( + self.projectDir, xtal, self.db_dict["CompoundCode"] + ".png" + ), + xtal, + self.db_dict["CompoundCode"] + ".png", + ) + ) + else: + self.Logfile.error( + "%s: cannot find compound png file -> %s" + % (xtal, self.db_dict["CompoundCode"] + ".png") + ) + + def copy_spider_plot(self, xtal, ligID): + os.chdir(os.path.join(self.htmlDir, "png")) + refPDB = os.path.join(self.projectDir, xtal, "refine.pdb") + self.Logfile.insert("%s: looking for spider plots..." % xtal) + if os.path.isfile(refPDB): + refPDBreal = os.path.realpath(refPDB)[: os.path.realpath(refPDB).rfind("/")] + plot = os.path.join( + refPDBreal, "residue_plots", ligID.replace("LIG-", "") + ".png" + ) + self.Logfile.insert(xtal + ": looking for " + plot) + if os.path.isfile(plot): + self.Logfile.insert("%s: found %s" % (xtal, plot)) + self.Logfile.insert( + "%s: copying spider plot for %s" + % (xtal, ligID.replace("LIG-", "") + ".png") + ) + os.system("/bin/cp %s %s_%s.png" % (plot, xtal, ligID)) + else: + self.Logfile.error( + "%s: cannot find spider plot for %s" + % (xtal, ligID.replace("LIG-", "") + ".png") + ) + self.Logfile.warning( + "%s: using %s instead" % (xtal, "NO_SPIDER_PLOT_AVAILABLE.png") + ) + os.system( + "/bin/cp %s %s_%s.png" + % ( + os.path.join( + os.getenv("XChemExplorer_DIR"), + "xce", + "image", + "NO_SPIDER_PLOT_AVAILABLE.png", + ), + xtal, + ligID, + ) + ) + # + else: + self.Logfile.error( + "%s: cannot find refine.pdb, i.e. cannot start looking for spider" + " plots..." % xtal + ) + + def write_html_file(self, html): + os.chdir(self.htmlDir) + self.Logfile.insert("writing index.html") + html += XChemMain.html_footer() + if os.path.isfile("index.html"): + os.system("/bin/rm -f index.html") + f = open("index.html", "w") + f.write(html) + f.close() diff --git a/xce/web/__init__.py b/xce/web/__init__.py new file mode 100755 index 00000000..e69de29b diff --git a/web/dsEvent_sqlite.icm b/xce/web/dsEvent_sqlite.icm similarity index 100% rename from web/dsEvent_sqlite.icm rename to xce/web/dsEvent_sqlite.icm diff --git a/web/jscss/css/custom-fragment.css b/xce/web/jscss/css/custom-fragment.css similarity index 100% rename from web/jscss/css/custom-fragment.css rename to xce/web/jscss/css/custom-fragment.css diff --git a/web/jscss/css/jquery.dataTables.min.css b/xce/web/jscss/css/jquery.dataTables.min.css similarity index 100% rename from web/jscss/css/jquery.dataTables.min.css rename to xce/web/jscss/css/jquery.dataTables.min.css diff --git a/web/jscss/js/create_view.js b/xce/web/jscss/js/create_view.js similarity index 100% rename from web/jscss/js/create_view.js rename to xce/web/jscss/js/create_view.js diff --git a/web/jscss/js/jquery-1.12.3.min.js b/xce/web/jscss/js/jquery-1.12.3.min.js similarity index 100% rename from web/jscss/js/jquery-1.12.3.min.js rename to xce/web/jscss/js/jquery-1.12.3.min.js diff --git a/web/jscss/js/jquery.dataTables.min.js b/xce/web/jscss/js/jquery.dataTables.min.js similarity index 100% rename from web/jscss/js/jquery.dataTables.min.js rename to xce/web/jscss/js/jquery.dataTables.min.js diff --git a/web/jscss/js/ngl.js b/xce/web/jscss/js/ngl.js old mode 100644 new mode 100755 similarity index 100% rename from web/jscss/js/ngl.js rename to xce/web/jscss/js/ngl.js diff --git a/xce/web/process_sqlite.py b/xce/web/process_sqlite.py new file mode 100755 index 00000000..82d9b150 --- /dev/null +++ b/xce/web/process_sqlite.py @@ -0,0 +1,512 @@ +import csv +import getopt +import glob +import os +import shutil +import sqlite3 +import sys +import zipfile + +from rdkit import Chem +from rdkit.Chem import Draw + +targetID = "" +panddadir = "" + + +def writeTableRow(row, htmlfile): + "Write a row of data to the HTML file" + htmlfile.write("") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write( + "\n" + ) + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write( + "\n" + ) + htmlfile.write( + "\n" + ) + htmlfile.write("\n") + htmlfile.write( + "\n".format(row["Deposition_PDB_ID"], row["Deposition_PDB_ID"]) + ) + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + return + + +def writeICBPage(row, panddadir): + "Write HTML file for ICB visualisation" + icbhtmlfile = open(panddadir + "/icbs/" + row["ModelName"] + ".html", "w") + icbhtmlfile.write("\n") + icbhtmlfile.write("\n") + icbhtmlfile.write( + '\n' + ) + icbhtmlfile.write( + '\n' + ) + icbhtmlfile.write('\n') + icbhtmlfile.write("" + row["ModelName"] + "\n") + icbhtmlfile.write("\n") + icbhtmlfile.write("\n") + icbhtmlfile.write( + "

" + row["CrystalName"] + " " + row["CompoundCode"] + " event

\n" + ) + icbhtmlfile.write( + '
' + '

' + "Please wait whilst the interactive viewer is loaded!" + "

" + "
\n" + ) + icbhtmlfile.write( + '
\n' + ) + icbhtmlfile.write( + '\n' + ) + icbhtmlfile.write("
\n") + icbhtmlfile.write('
\n') + icbhtmlfile.write("
Crystal IDPDB IDLigand IDLigand confidenceModel statusCompoundLigand ValidationEvent Map 3DResolSPG/ CellFiles
%s%s%s%s%s +
+
%s%s
%s
Save
" + row["ModelName"] + "" + row["CompoundSMILES"] + "" + row["PANDDA_site_name"] + "" + row["LigandConfidence"] + "" + row["ModelStatus"] + "
" + row["PANDDA_site_comment"] + "" + '' + "{1!s}" + "" + "" + row["DataProcessingResolutionHigh"] + "" + row["DataProcessingSpaceGroup"] + "" + row["DataProcessingUnitCell"] + "SaveSaveSave
\n") + icbhtmlfile.write("\n") + icbhtmlfile.write( + "\n" + ) + icbhtmlfile.write( + "\n" + ) + icbhtmlfile.write("
Protein: " + row["CrystalName"] + "
Compound ID: " + + row["CompoundCode"] + + "
Compound SMILES: " + + row["CompoundSMILES"] + + "
\n") + icbhtmlfile.write("
\n") + icbhtmlfile.write("\n") + icbhtmlfile.write("\n") + icbhtmlfile.write("\n") + icbhtmlfile.close() + return + + +def main(argv): + sqlitefile = "" + # Process command line options + try: + opts, args = getopt.getopt( + argv, "t:s:d:", ["targetID=", "sqlitefile=", "panddadir="] + ) + except getopt.GetoptError as err: + print(err) + print("process.py -t -s -d ") + sys.exit(2) + if len(opts) < 3: + print("Missing arguments:") + print("process.py -t -s -d ") + sys.exit(2) + for opt, arg in opts: + if opt == "-h": + print("process.py -t -s ") + sys.exit() + elif opt in ("-t", "--targetID"): + targetID = arg + elif opt in ("-s", "--sqlitefile"): + sqlitefile = arg + elif opt in ("-d", "--panddadir"): + panddadir = arg + + # Create directory structure + if not os.path.exists(panddadir + "/compoundImages"): + os.makedirs(panddadir + "/compoundImages") + if not os.path.exists(panddadir + "/icbs"): + os.makedirs(panddadir + "/icbs") + if not os.path.exists(panddadir + "/pdbs"): + os.makedirs(panddadir + "/pdbs") + if not os.path.exists(panddadir + "/maps"): + os.makedirs(panddadir + "/maps") + if not os.path.exists(panddadir + "/residueplots"): + os.makedirs(panddadir + "/residueplots") + if not os.path.exists(panddadir + "/mapImages"): + os.makedirs(panddadir + "/mapImages") + + # Create HTML file and write header + htmlfile = open(panddadir + "/index.html", "w") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write( + '\n' + ) + htmlfile.write( + '\n' + ) + htmlfile.write( + '\n' + ) + htmlfile.write("" + targetID + " Fragment Hits\n") + htmlfile.write( + '\n") + htmlfile.write( + '\n") + htmlfile.write('\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("

Ligand-bound models for " + targetID + "

") + htmlfile.write( + "

Interpreting 'Ligand confidence'

\n" + "

4 - High Confidence: The expected ligand was easily interpretable" + " from clear density, and subsequent refinement was well-behaved. This ligand" + " can be trusted.\n" + "
3 - Clear density, unexpected ligand: Density very clearly showed" + " a well-defined ligand, but that ligand was unexpected in that" + " crystal/dataset. The observed ligand was modelled anyway, because its" + " presence could be explained in some way.\n" + "
2 - Correct ligand, weak density: Though density was weak, it was" + " possible to model the expected ligand, possibly including other" + " circumstantial evidence (e.g. similar ligand in another model).\n" + "
1 - Low Confidence: The ligand model is to be treated with" + " scepticism, because the evidence (density, identity, pose) were not" + " convincing.\n" + "

Interpreting 'Model status':

\n" + "

6 - Deposited: The model has been deposited in the PDB.\n" + "
5 - Deposition ready: The model is fully error-free, in every" + " residue, and is ready for deposition.\n" + "
4 - CompChem ready: The model is complete and correct in the" + " region of the bound ligand. There may be remaining small errors elsewhere in" + " the structure, but they are far away and unlikely to be relevant to any" + " computational analysis or compound design.\n" + "

Interpreting 'Ligand validation' spider plots:

Each axis represents" + " one of the values described below; small is better, and large values on any" + " axis implies that further investigation is warranted.\n" + "

Quality (RSCC) reflects the fit of the atoms to the experimental" + " density, and should typically be greater than 0.7.\n" + "
Accuracy (RSZD) measures the amount of difference density that is" + " found around these atoms, and should be below 3.\n" + "
B-factor ratio measures the consistency of the model with" + " surrounding protein, and is calculated from the B factors of respectively the" + " changed atoms and all side-chain atoms within 4Å. Large values (>3)" + " reflect poor evidence for the model, and intermediate values (1.5+) indicate" + " errors in refinement or modelling; for weakly-binding ligands, systematically" + " large ratios may be justifiable.\n" + "
RMSD compares the positions of all atoms built into event density," + " with their positions after final refinement, and should be below 1Å.\n" + "
Precision (RSZO/OCC) measures how clear the density is after" + " refinement. (This is not a quality indicator, but is related to strength of" + " binding but not in a straightforward way.)\n" + "

\n\n" + ) + htmlfile.write("

Download data

\n") + htmlfile.write("
") + htmlfile.write('\n') + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.write("\n") + + # Now walk through the input data + with open("foricm.csv", "wb") as f: + with sqlite3.connect(sqlitefile) as connection: + connection.row_factory = sqlite3.Row + cur = connection.cursor() + + sql = ( + "select p.ID," + "p.CrystalName," + "p.PANDDA_site_event_index," + "p.CrystalName || '_event'|| p.PANDDA_site_event_index " + " as ModelName," + "m.CompoundCode," + "m.CompoundSMILES," + "m.Deposition_PDB_ID," + "p.PANDDA_site_name," + " p.PANDDA_site_confidence as LigandConfidence," + " p.RefinementOutcome as ModelStatus," + " p.PANDDA_site_comment," + "p.PANDDA_site_x," + "p.PANDDA_site_y," + "p.PANDDA_site_z," + " p.PANDDA_site_spider_plot," + " m.DataProcessingResolutionHigh," + "m.DataProcessingSpaceGroup," + "m.DataProcessingUnitCell," + " m.RefinementBoundConformation," + "m.RefinementMTZ_latest," + " p.PANDDA_site_event_map from panddaTable as p, " + " mainTable as m" + " where p.CrystalName=m.CrystalName" + " and p.PANDDA_site_ligand_placed='True' " + " and (p.RefinementOutcome like '4%'" + " or p.RefinementOutcome like '5%'" + " or p.RefinementOutcome like '6%') " + " and (LigandConfidence like '1%'" + " or LigandConfidence like '2%'" + " or LigandConfidence like '3%'" + " or LigandConfidence like '4%')" + " order by p.CrystalName,ModelStatus desc,PANDDA_site_event_index" + ) + + sql = ( + "select p.ID," + "p.CrystalName," + "p.PANDDA_site_event_index," + "p.CrystalName || '_event'|| p.PANDDA_site_event_index " + " as ModelName," + "m.CompoundCode," + "m.CompoundSMILES," + "m.Deposition_PDB_ID," + "p.PANDDA_site_name," + " p.PANDDA_site_confidence as LigandConfidence," + " p.RefinementOutcome as ModelStatus," + " p.PANDDA_site_comment," + "p.PANDDA_site_x," + "p.PANDDA_site_y," + "p.PANDDA_site_z," + " p.PANDDA_site_spider_plot," + " m.DataProcessingResolutionHigh," + "m.DataProcessingSpaceGroup," + "m.DataProcessingUnitCell," + " m.RefinementBoundConformation," + "m.RefinementMTZ_latest," + " p.PANDDA_site_event_map" + " from panddaTable as p, " + " mainTable as m" + " where p.CrystalName=m.CrystalName" + " and p.PANDDA_site_ligand_placed='True' " + " and (m.RefinementOutcome like '4%'" + " or m.RefinementOutcome like '5%'" + " or m.RefinementOutcome like '6%') " + " and (LigandConfidence like '1%'" + " or LigandConfidence like '2%'" + " or LigandConfidence like '3%'" + " or LigandConfidence like '4%')" + " order by p.CrystalName,ModelStatus desc,PANDDA_site_event_index" + ) + + cur.execute(sql) + + rows = cur.fetchall() + if not rows: + print( + "==> WARNING: none of your samples seems to be at least" + " CompChem ready (4)" + ) + return None + writer = csv.DictWriter(f, fieldnames=list(rows[1].keys())) + writer.writeheader() + for row in rows: + # Make compound structure + print(row["ModelName"], row["PANDDA_site_spider_plot"]) + compound = Chem.MolFromSmiles(row["CompoundSMILES"].encode("ascii")) + Draw.MolToFile( + compound, + panddadir + "/compoundImages/" + row["CompoundCode"] + ".png", + (150, 150), + ) + # Write out table information for event + writeTableRow(row, htmlfile) + writeICBPage(row, panddadir) + try: + shutil.copy( + row["RefinementBoundConformation"], + panddadir + "/pdbs/" + row["ModelName"] + ".pdb", + ) + shutil.copy( + row["RefinementMTZ_latest"], + panddadir + "/maps/" + row["ModelName"] + ".mtz", + ) + shutil.copy( + row["PANDDA_site_event_map"], + panddadir + "/maps/" + row["ModelName"] + ".ccp4", + ) + if row["PANDDA_site_spider_plot"] is not None: + shutil.copy( + row["PANDDA_site_spider_plot"], + panddadir + "/residueplots/" + row["ModelName"] + ".png", + ) + except (IOError, TypeError): + print( + "*** WARNING: cannot find PDB and/or MTZ of " + + row["ModelName"] + + " ***" + ) + print("PDB bound :", row["RefinementBoundConformation"]) + print("MTZ :", row["RefinementMTZ_latest"]) + print("event map :", row["PANDDA_site_event_map"]) + print("spider plot:", row["PANDDA_site_spider_plot"]) + pass + # Write row to CSV for ICM + writer.writerow(dict(row)) + + # Conclude HTML + htmlfile.write("\n") + htmlfile.write("
Model NameCompound SMILESCompound StructureSite NameLigand ConfidenceModel StatusLigand ValidationEvent Map 3DCommentPDB IdentifierResolSpacegroupCellPDBMTZEvent Map
Model NameCompound SMILESCompound StructureSite NameLigand ConfidenceModel StatusLigand ValidationEvent Map 3DCommentPDB IdentifierResolSpacegroupCellPDBMTZEvent Map
\n") + htmlfile.write("\n") + htmlfile.write("\n") + htmlfile.close() + + # Copy JS & CSS files + if not os.path.exists(panddadir + "/js"): + os.makedirs(panddadir + "/js") + if not os.path.exists(panddadir + "/css"): + os.makedirs(panddadir + "/css") + shutil.copy( + os.path.join( + os.getenv("XChemExplorer_DIR"), "web/jscss/css/jquery.dataTables.min.css" + ), + panddadir + "/css/jquery.dataTables.min.css", + ) + shutil.copy( + os.path.join( + os.getenv("XChemExplorer_DIR"), "web/jscss/js/jquery-1.12.3.min.js" + ), + panddadir + "/js/jquery-1.12.3.min.js", + ) + shutil.copy( + os.path.join( + os.getenv("XChemExplorer_DIR"), "web/jscss/js/jquery.dataTables.min.js" + ), + panddadir + "/js/jquery.dataTables.min.js", + ) + + # Create zip files + print("Creating zipfile of PDBs...") + os.chdir(panddadir + "/pdbs") + zf = zipfile.ZipFile("allPDBs.zip", "w") + for pdb in glob.glob("*.pdb"): + zf.write(pdb) + zf.close() + + print("Creatig zipfile of event maps...") + os.chdir("../maps") + zf = zipfile.ZipFile("allEventMaps.zip", "w") + for pdb in glob.glob("*.mtz"): + zf.write(pdb) + zf.close() + + # change folder permissions + os.system("chmod -R 775 {0!s}".format(panddadir)) + + return + + +if __name__ == "__main__": + main(sys.argv[1:])