diff --git a/docs/Writerside/images/example-snfg.png b/docs/Writerside/images/example-snfg.png
new file mode 100644
index 0000000..46cd98e
Binary files /dev/null and b/docs/Writerside/images/example-snfg.png differ
diff --git a/docs/Writerside/topics/Automated-Glycan-Building.topic b/docs/Writerside/topics/Automated-Glycan-Building.topic
index 2ff953d..a362029 100644
--- a/docs/Writerside/topics/Automated-Glycan-Building.topic
+++ b/docs/Writerside/topics/Automated-Glycan-Building.topic
@@ -30,9 +30,9 @@
Advanced Example:
- Attempt to build N-glycans into ABCD.cif with structure factors.
+ Attempt to build O-mannoses into ABCD.cif with structure factors.
- sails -pdbin ABCD.cif -mtzin ABCD-sf.cif.gz -cycles 4 -colin-fo F,SIGF -nglycan
+ sails -pdbin ABCD.cif -mtzin ABCD-sf.cif.gz -type o-mannosylate -cycles 1 -colin-fo F,SIGF
@@ -51,30 +51,33 @@
Path to output CIF file.
- Default: sails-model-out.cif
+ Default: sails-model-out.cif
Path to output MTZ file.
- Default: sails-refln-out.mtz
+ Default: sails-refln-out.mtz
Path to output MTZ file.
- Default: sails-log.json
+ Default: sails-log.json
Number of internal cycles to run.
- Default: 2
+ Default: 2
-
- Build N-glycans into the given structure
- Default Option
+
+ Type of glycosylation
+ Options:
+
+ n-glycosylate
+ c-glycosylate
+ o-mannosylate
+
+ Default: n-glycosylate
-
- Build C-glycans (tryptophan mannosylation) into the given structure
-
Comma separated SF observations and associated uncertainty.
- Default: FP,SIGFP
+ Default: FP,SIGFP
Comma separated SF weight and associated phase.
diff --git a/docs/Writerside/topics/Generate-SNFG-Diagrams.topic b/docs/Writerside/topics/Generate-SNFG-Diagrams.topic
index 92029c2..6c056ce 100644
--- a/docs/Writerside/topics/Generate-SNFG-Diagrams.topic
+++ b/docs/Writerside/topics/Generate-SNFG-Diagrams.topic
@@ -6,10 +6,15 @@
title="Generate SNFG Diagrams" id="Generate-SNFG-Diagrams" help-id="Generate-SNFG-Diagrams">
- Sails provides a fast utility tool to generate SNFG diagrams using Sails' internal diagram engine. A specific
+ Sails provides a fast utility tool to generate Symbol Nomeclature for Glycans Diagram (SNFG) diagrams using Sails' internal diagram engine. A specific
site can be specified with -chain and -seqid parameters, or, all the detectable SNFGs will be generated.
+
+ Example SNFG Diagram for a high mannose glycan
+
+
+
Syntax:
@@ -27,6 +32,7 @@
sails-snfg -model built.cif --all -snfgout snfgs
+
Describe what each option is used for:
diff --git a/package/src/bindings/python_sails.cpp b/package/src/bindings/python_sails.cpp
index 0ce3660..5741c94 100644
--- a/package/src/bindings/python_sails.cpp
+++ b/package/src/bindings/python_sails.cpp
@@ -147,6 +147,8 @@ NB_MODULE(sails_module, m) {
m.def("n_glycosylate_from_objects", &n_glycosylate, "structure"_a, "mtz"_a, "cycles"_a, "resource_dir"_a, "verbose"_a);
m.def("c_glycosylate_from_objects", &c_glycosylate, "structure"_a, "mtz"_a, "cycles"_a, "resource_dir"_a, "verbose"_a);
+ m.def("o_mannosylate_from_objects", &o_mannosylate, "structure"_a, "mtz"_a, "cycles"_a, "resource_dir"_a, "verbose"_a);
+
m.def("test_snfg", &test);
m.def("get_snfg", &get_snfg, "chain"_a, "seqid"_a , "structure"_a, "resource_dir"_a);
diff --git a/package/src/cpp/sails-density.cpp b/package/src/cpp/sails-density.cpp
index 9d23d86..6e14e6d 100644
--- a/package/src/cpp/sails-density.cpp
+++ b/package/src/cpp/sails-density.cpp
@@ -170,7 +170,7 @@ void Sails::Density::recalculate_map(gemmi::Structure &structure) {
new_mtz.add_column("FWT", 'F', -1, -1, true);
new_mtz.add_column("PHWT", 'P', -1, -1, true);
new_mtz.add_column("DELFWT", 'F', -1, -1, true);
- new_mtz.add_column("PHDELWT", 'P', -1, -1, true);;
+ new_mtz.add_column("PHDELWT", 'P', -1, -1, true);
new_mtz.set_data(recalculated_data.data(), recalculated_data.size());
new_mtz.ensure_asu();
@@ -217,7 +217,7 @@ void Sails::Density::calculate_po_pc_map(gemmi::Structure &structure) {
new_mtz.add_dataset("SAILS");
new_mtz.add_base();
new_mtz.add_column("FDIFFCALC", 'F', -1, -1, true);
- new_mtz.add_column("PDIFFCALC", 'P', -1, -1, true);;
+ new_mtz.add_column("PDIFFCALC", 'P', -1, -1, true);
new_mtz.set_data(recalculated_data.data(), recalculated_data.size());
new_mtz.ensure_asu();
diff --git a/package/src/cpp/sails-linkage.cpp b/package/src/cpp/sails-linkage.cpp
index 6942222..2d283e0 100644
--- a/package/src/cpp/sails-linkage.cpp
+++ b/package/src/cpp/sails-linkage.cpp
@@ -134,7 +134,6 @@ void Sails::Model::remove_leaving_atom(Sails::LinkageData &data, gemmi::Residue
void Sails::Model::add_sugar_to_structure(const Sugar *terminal_sugar, SuperpositionResult &favoured_addition,
ChainType &chain_type) {
int chain_idx = terminal_sugar->site.chain_idx;
- int residue_idx = terminal_sugar->site.residue_idx;
if (chain_type == protein) {
const size_t last_chain_idx = structure->models[terminal_sugar->site.model_idx].chains.size();
@@ -142,7 +141,6 @@ void Sails::Model::add_sugar_to_structure(const Sugar *terminal_sugar, Superposi
gemmi::Chain chain;
chain.name = Utils::get_next_string(
structure->models[terminal_sugar->site.model_idx].chains[last_chain_idx - 1].name);
- residue_idx = -1;
structure->models[terminal_sugar->site.model_idx].chains.emplace_back(chain);
}
@@ -220,8 +218,8 @@ std::optional Sails::Model::add_residue(
auto library_monomer = get_monomer(data.acceptor, true);
if (!library_monomer.has_value()) { throw std::runtime_error("Could not get required monomer, "
- "ensure that CCP4 monomer library is sourced."
- "If you have a local monomer library, ensure that you"
+ "ensure that CCP4 monomer library is sourced. "
+ "If you have a local monomer library, ensure that you "
"have CLIBD set"); }
auto reference_library_monomer = gemmi::Residue(library_monomer.value());
@@ -338,7 +336,7 @@ void Sails::Model::extend_if_possible(Density &density, bool debug, ChainType &c
if (!opt_result.has_value()) {
if (debug) print_rejection_log();
continue;
- };
+ }
possible_additions[data.donor_number].emplace_back(opt_result.value());
diff --git a/package/src/cpp/sails-sequence.cpp b/package/src/cpp/sails-sequence.cpp
index de41802..bd8ce35 100644
--- a/package/src/cpp/sails-sequence.cpp
+++ b/package/src/cpp/sails-sequence.cpp
@@ -4,14 +4,11 @@
#include "../include/sails-sequence.h"
Sails::Glycosites Sails::find_n_glycosylation_sites(const gemmi::Structure &structure) {
-
std::vector glycosites;
auto models = structure.children();
for (int model_idx = 0; model_idx < models.size(); model_idx++) {
-
auto chains = models[model_idx].children();
for (int chain_idx = 0; chain_idx < chains.size(); chain_idx++) {
-
auto residues = chains[chain_idx].children();
// if there are less than three residues, skip
@@ -19,13 +16,13 @@ Sails::Glycosites Sails::find_n_glycosylation_sites(const gemmi::Structure &stru
for (int residue_idx = 0; residue_idx < residues.size() - 2; residue_idx++) {
char first = gemmi::find_tabulated_residue(residues[residue_idx].name).one_letter_code;
- if (first != 'N') {continue;}
+ if (first != 'N') { continue; }
char third = gemmi::find_tabulated_residue(residues[residue_idx + 2].name).one_letter_code;
- if (third != 'S' && third != 'T') {continue;}
+ if (third != 'S' && third != 'T') { continue; }
char second = gemmi::find_tabulated_residue(residues[residue_idx + 1].name).one_letter_code;
- if (second == 'P') {continue;}
+ if (second == 'P') { continue; }
glycosites.emplace_back(model_idx, chain_idx, residue_idx);
}
@@ -39,24 +36,46 @@ Sails::Glycosites Sails::find_c_glycosylation_sites(const gemmi::Structure &stru
std::vector glycosites;
auto models = structure.children();
for (int model_idx = 0; model_idx < models.size(); model_idx++) {
-
auto chains = models[model_idx].children();
for (int chain_idx = 0; chain_idx < chains.size(); chain_idx++) {
-
auto residues = chains[chain_idx].children();
// if there are less than three residues, skip
if (residues.size() < 4) continue;
for (int residue_idx = 0; residue_idx < residues.size() - 3; residue_idx++) {
-
char first = gemmi::find_tabulated_residue(residues[residue_idx].name).one_letter_code;
- if (first != 'W') {continue;}
+ if (first != 'W') { continue; }
char fourth = gemmi::find_tabulated_residue(residues[residue_idx + 3].name).one_letter_code;
- if (fourth != 'W') {continue;}
+ if (fourth != 'W') { continue; }
glycosites.emplace_back(model_idx, chain_idx, residue_idx);
- glycosites.emplace_back(model_idx, chain_idx, residue_idx+3);
+ glycosites.emplace_back(model_idx, chain_idx, residue_idx + 3);
+ }
+ }
+ }
+
+ return glycosites;
+}
+
+Sails::Glycosites Sails::find_o_mannosylation_sites(const gemmi::Structure &structure,
+ std::map &solvent_accessibility_map) {
+ std::vector glycosites;
+ auto models = structure.children();
+ for (int model_idx = 0; model_idx < models.size(); model_idx++) {
+ auto chains = models[model_idx].children();
+ for (int chain_idx = 0; chain_idx < chains.size(); chain_idx++) {
+ auto residues = chains[chain_idx].children();
+ // if there are less than three residues, skip
+ if (residues.size() < 4) continue;
+ for (int residue_idx = 0; residue_idx < residues.size() - 3; residue_idx++) {
+ std::string name = residues[residue_idx].name;
+ if (name != "SER" && name != "THR") continue;
+ Glycosite g = {model_idx, chain_idx, residue_idx};
+ double solvent_accessibility = solvent_accessibility_map[g];
+ if (solvent_accessibility > 10) {
+ glycosites.emplace_back(g);
+ }
}
}
}
diff --git a/package/src/cpp/sails-telemetry.cpp b/package/src/cpp/sails-telemetry.cpp
index 4d93fe8..a8c70d5 100644
--- a/package/src/cpp/sails-telemetry.cpp
+++ b/package/src/cpp/sails-telemetry.cpp
@@ -65,13 +65,4 @@ std::optional Sails::Telemetry::format_log(gemmi::Structure *struct
return stream.str();
}
return std::nullopt;
-
- // for (const auto &[cycle, entries]: log) {
- // std::cout << "Cycle " << cycle << "\n";
- // for (const auto &entry: entries) {
- // std::cout << "Added " << entry.residue_id << "\t" << entry.rscc_score << "\t" << entry.rsr_score << "\t"
- // << entry.dds_score << "\n";
- // }
- // std::cout << std::endl;
- // }
}
diff --git a/package/src/cpp/sails-topology.cpp b/package/src/cpp/sails-topology.cpp
index af4932a..7a38fc9 100644
--- a/package/src/cpp/sails-topology.cpp
+++ b/package/src/cpp/sails-topology.cpp
@@ -105,7 +105,7 @@ void Sails::Topology::find_residue_near_donor(Glycosite &glycosite, Glycan &glyc
// }
// std::cout << std::endl;
continue;
- };
+ }
// Add the sugar, and then linkage
// This is required to ensure the sugar objects live until the Glycan goes out of scope.
diff --git a/package/src/cpp/sails.cpp b/package/src/cpp/sails.cpp
index 7f6c12c..0e36327 100644
--- a/package/src/cpp/sails.cpp
+++ b/package/src/cpp/sails.cpp
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
void print_rejection_dds(const Sails::Glycosite& s1, const Sails::Glycosite& s2, gemmi::Structure* structure, float score) {
@@ -30,9 +31,10 @@ void print_removal_rscc(const gemmi::Residue& residue, float rscc) {
std::cout << "Removing " << Sails::Utils::format_residue_key(&residue) << " because of low RSCC =" << rscc << std::endl;
}
-void remove_erroneous_sugars(gemmi::Structure *structure, Sails::Density *density, Sails::Glycan *glycan, bool debug) {
- constexpr float rscc_threshold = 0.5;
- constexpr float dds_threshold = 1.1;
+void remove_erroneous_sugars(gemmi::Structure *structure, Sails::Density *density, Sails::Glycan *glycan, bool strict,
+ bool debug) {
+ const float rscc_threshold = strict ? 0.65: 0.5;
+ const float dds_threshold = strict ? 1.0: 1.1;
std::vector to_remove;
for (const auto &[fst, snd]: *glycan) {
@@ -96,8 +98,8 @@ void check_spacegroup(gemmi::Mtz* mtz, gemmi::Structure* structure) {
if (mtz->spacegroup_name.empty()) mtz->spacegroup_name = structure->spacegroup_hm;
}
-Sails::Output run_cycle(Sails::Glycosites& glycosites, gemmi::Structure &structure, Sails::MTZ &sails_mtz, int cycles, std::string &
- resource_dir, bool verbose) {
+Sails::Output run_cycle(Sails::Glycosites &glycosites, gemmi::Structure &structure, Sails::MTZ &sails_mtz, int cycles,
+ std::string &resource_dir, bool strict, bool verbose) {
std::string data_file = resource_dir + "/data.json";
Sails::JSONLoader loader = {data_file};
@@ -153,7 +155,7 @@ Sails::Output run_cycle(Sails::Glycosites& glycosites, gemmi::Structure &structu
// std::cout << "Attempting removal at " << Sails::Utils::format_residue_from_site(glycosite, &structure) << std::endl;
Sails::Glycan old_glycan = glycan;
- remove_erroneous_sugars(&structure, &density, &glycan, verbose);
+ remove_erroneous_sugars(&structure, &density, &glycan, strict, verbose);
topology.set_structure(&structure); // need to update neighbor search after removing n residues
Sails::Glycan new_glycan = topology.find_glycan_topology(glycosite);
@@ -189,13 +191,21 @@ Sails::Output run_cycle(Sails::Glycosites& glycosites, gemmi::Structure &structu
Sails::Output n_glycosylate(gemmi::Structure &structure, Sails::MTZ &sails_mtz, int cycles, std::string &resource_dir,
bool verbose) {
auto glycosites = Sails::find_n_glycosylation_sites(structure);
- return run_cycle(glycosites, structure, sails_mtz, cycles, resource_dir, verbose);
+ return run_cycle(glycosites, structure, sails_mtz, cycles, resource_dir, false, verbose);
}
Sails::Output c_glycosylate(gemmi::Structure &structure, Sails::MTZ &sails_mtz, int cycles, std::string &resource_dir,
bool verbose) {
auto glycosites = Sails::find_c_glycosylation_sites(structure);
- return run_cycle(glycosites, structure, sails_mtz, cycles, resource_dir, verbose);
+ return run_cycle(glycosites, structure, sails_mtz, cycles, resource_dir, false, verbose);
+}
+
+Sails::Output o_mannosylate(gemmi::Structure &structure, Sails::MTZ &sails_mtz, int cycles, std::string &resource_dir,
+ bool verbose) {
+ Sails::SolventAccessibility sa = Sails::SolventAccessibility(&structure);
+ Sails::SolventAccessibility::SolventAccessibilityMap sa_map = sa.calculate_solvent_accessibility();
+ auto glycosites = Sails::find_o_mannosylation_sites(structure, sa_map);
+ return run_cycle(glycosites, structure, sails_mtz, cycles, resource_dir, false, verbose);
}
std::string get_snfg(std::string chain, int seqid, gemmi::Structure& structure, std::string& resource_dir) {
@@ -244,28 +254,26 @@ std::map get_all_snfgs(gemmi::Structure& structure, st
}
void test() {
- const std::string path = "testing/test_data/5fji/5FJI.cif";
- const std::string mtz_path = "testing/test_data/5fji/5fji.mtz";
-
+ const std::string path = "testing/test_data/4ax7/4AX7_deglycosylated.cif";
+ const std::string mtz_path = "testing/test_data/4ax7/4AX7.mtz";
+ gemmi::Mtz mtz = gemmi::read_mtz_file(mtz_path);
+ auto smtz = Sails::form_sails_mtz(mtz, "FP", "SIGFP");
gemmi::Structure structure = gemmi::read_structure_file(path);
std::string data_file = "package/src/sails/data/data.json";
Sails::JSONLoader loader = {data_file};
Sails::ResidueDatabase residue_database = loader.load_residue_database();
- auto snfg = Sails::SNFG(&structure, &residue_database);
- Sails::Topology topology = {&structure, residue_database};
- auto glycosites = Sails::find_n_glycosylation_sites(structure);
+ Sails::Density density = Sails::Density(mtz);
+ density.load_hkl("FP", "SIGFP");
+ density.recalculate_map(structure);
- for (auto& site: glycosites) {
- // auto site = glycosites[4];
- auto glycan = topology.find_glycan_topology(site);
- if (glycan.empty()) continue;
- std::string snfg_path = "snfgs/" + Sails::Utils::format_residue_from_site(site, &structure) + ".svg";
- std::ofstream f(snfg_path);
- f << snfg.create_snfg(glycan, site);
- f.close();
- }
+
+// auto o = find_o_mannosylation_sites(structure, sa_map);
+// std::string a = "package/src/sails/data";
+// auto output = run_cycle(o, structure, smtz, 1, a, true, true);
+// Sails::Utils::save_structure_to_file(output.structure, "o-mannose-strict.cif");
+// std::cout << output.log << std::endl;
}
// testbed
diff --git a/package/src/include/sails-glycan.h b/package/src/include/sails-glycan.h
index cac60ff..b5d50e7 100644
--- a/package/src/include/sails-glycan.h
+++ b/package/src/include/sails-glycan.h
@@ -43,7 +43,7 @@ namespace Sails {
acceptor_atom(acceptor_atom) {
std::string donor_number_s = {donor_atom[donor_atom.size()-1]};
- donor_number = std::stoi(donor_number_s);
+ donor_number = std::isdigit(donor_number_s[0]) ? std::stoi(donor_number_s): 1;
}
Sugar *donor_sugar;
diff --git a/package/src/include/sails-sequence.h b/package/src/include/sails-sequence.h
index ac3b68c..17f0229 100644
--- a/package/src/include/sails-sequence.h
+++ b/package/src/include/sails-sequence.h
@@ -41,6 +41,10 @@ namespace Sails {
* If no C-glycosylation sites are found, an empty vector is returned.
*/
Glycosites find_c_glycosylation_sites(const gemmi::Structure &structure);
+
+
+
+ Glycosites find_o_mannosylation_sites(const gemmi::Structure& structure, std::map& solvent_accessibility_map);
}
#endif //SAILS_SAILS_SEQUENCE_H
diff --git a/package/src/include/sails-solvent.h b/package/src/include/sails-solvent.h
index cbd6a5e..fd48988 100644
--- a/package/src/include/sails-solvent.h
+++ b/package/src/include/sails-solvent.h
@@ -57,7 +57,7 @@ namespace Sails {
*
* @return A map containing the solvent accessibility value for each glycosite.
*/
- std::map calculate_solvent_accessibility();
+ [[nodiscard]] std::map calculate_solvent_accessibility();
/**
* @brief Calculates the bounding box of the structure.
diff --git a/package/src/sails/__init__.py b/package/src/sails/__init__.py
index 127d44f..061e2a3 100644
--- a/package/src/sails/__init__.py
+++ b/package/src/sails/__init__.py
@@ -1,7 +1,7 @@
from .sails_module import (HKL, Reflection, Pair, Structure, Model, Chain, Residue, Atom, Position, Element, SeqId,
- n_glycosylate_from_objects, c_glycosylate_from_objects, Cell, MTZ, GlycoSite, Dot, test_snfg,
- get_snfg, get_all_snfgs)
+ n_glycosylate_from_objects, c_glycosylate_from_objects, o_mannosylate_from_objects,
+ Cell, MTZ, GlycoSite, Dot, test_snfg, get_snfg, get_all_snfgs)
from .__version__ import __version__
-from .glycosylate import glycosylate
+from .glycosylate import glycosylate, Type
from .interface import extract_gemmi_mtz, extract_sails_mtz, extract_gemmi_structure, extract_sails_structure, \
get_sails_structure, get_sails_mtz
diff --git a/package/src/sails/data/data.json b/package/src/sails/data/data.json
index 3426d88..45f92d6 100644
--- a/package/src/sails/data/data.json
+++ b/package/src/sails/data/data.json
@@ -174,8 +174,41 @@
}
],
"acceptorSets": []
+ },
+ {
+ "name": "SER",
+ "snfgShape": "square",
+ "snfgColour": "white",
+ "preferredDepths": [
+ 0
+ ],
+ "donorSets": [
+ {
+ "atom1": "CA",
+ "atom2": "CB",
+ "atom3": "OG",
+ "identifier": 1
+ }
+ ],
+ "acceptorSets": []
+ },
+ {
+ "name": "THR",
+ "snfgShape": "square",
+ "snfgColour": "white",
+ "preferredDepths": [
+ 0
+ ],
+ "donorSets": [
+ {
+ "atom1": "CA",
+ "atom2": "CB",
+ "atom3": "OG1",
+ "identifier": 1
+ }
+ ],
+ "acceptorSets": []
}
-
],
"linkages": [
{
@@ -232,20 +265,74 @@
"clusters": [
{
"angles": {
- "alphaMean": 120,
- "alphaStdDev": 10,
- "betaMean": 115,
- "betaStdDev": 10,
- "gammaMean": 110,
- "gammaStdDev": 10
+ "alphaMean": 127.838,
+ "alphaStdDev": 5.582,
+ "betaMean": 109.84,
+ "betaStdDev": 5.582,
+ "gammaMean": 116.699,
+ "gammaStdDev": 2.541
+ },
+ "torsions": {
+ "phiMean": 116.884,
+ "phiStdDev": 25.889,
+ "psiMean": -176.651,
+ "psiStdDev": 11.025,
+ "omegaMean": 162.145,
+ "omegaStdDev": 35.401
+ }
+ }
+ ]
+ },
+ {
+ "donorResidue": "SER",
+ "acceptorResidue": "MAN",
+ "donorNumber": 1,
+ "acceptorNumber": 1,
+ "length": 1.4,
+ "clusters": [
+ {
+ "angles": {
+ "alphaMean": 113.548,
+ "alphaStdDev": 5.876,
+ "betaMean": 111.95,
+ "betaStdDev": 5.876,
+ "gammaMean": 114.725,
+ "gammaStdDev": 1.774
+ },
+ "torsions": {
+ "phiMean": 72.866,
+ "phiStdDev": 28.094,
+ "psiMean": 175.3,
+ "psiStdDev": 33.92,
+ "omegaMean": 60.137,
+ "omegaStdDev": 10.249
+ }
+ }
+ ]
+ },
+ {
+ "donorResidue": "THR",
+ "acceptorResidue": "MAN",
+ "donorNumber": 1,
+ "acceptorNumber": 1,
+ "length": 1.4,
+ "clusters": [
+ {
+ "angles": {
+ "alphaMean": 113.367,
+ "alphaStdDev": 6.634,
+ "betaMean": 111.89,
+ "betaStdDev": 6.634,
+ "gammaMean": 114.592,
+ "gammaStdDev": 2.038
},
"torsions": {
- "phiMean": 130,
- "phiStdDev": 15,
- "psiMean": 180,
- "psiStdDev": 15,
- "omegaMean": 180,
- "omegaStdDev": 15
+ "phiMean": 86.251,
+ "phiStdDev": 27.802,
+ "psiMean": 130.215,
+ "psiStdDev": 25.722,
+ "omegaMean": 61.975,
+ "omegaStdDev": 11.282
}
}
]
diff --git a/package/src/sails/glycosylate.py b/package/src/sails/glycosylate.py
index 8fc5e37..f9ba921 100644
--- a/package/src/sails/glycosylate.py
+++ b/package/src/sails/glycosylate.py
@@ -1,7 +1,9 @@
import argparse
+import enum
import logging
from typing import Tuple, Callable, List
-from sails import (interface, n_glycosylate_from_objects, c_glycosylate_from_objects, Dot, GlycoSite, __version__)
+from sails import (interface, n_glycosylate_from_objects, c_glycosylate_from_objects, o_mannosylate_from_objects, Dot,
+ GlycoSite, __version__)
import time
import gemmi
from pathlib import Path
@@ -9,8 +11,37 @@
import importlib.resources
+class Type(enum.IntEnum):
+ n_glycosylate = 1
+ c_glycosylate = 2
+ o_mannosylate = 3
+
+ def __str__(self):
+ return self.name
+
+ @staticmethod
+ def from_string(s: str):
+ try:
+ return Type[s]
+ except KeyError:
+ raise ValueError("Invalid Type")
+
+
+def map_type_to_function(type: Type):
+ if type == Type.n_glycosylate:
+ return n_glycosylate_from_objects
+
+ if type == Type.c_glycosylate:
+ return c_glycosylate_from_objects
+
+ if type == Type.o_mannosylate:
+ return o_mannosylate_from_objects
+
+ raise TypeError("Type not found")
+
+
def glycosylate(structure: gemmi.Structure | Path | str, mtz: gemmi.Mtz | Path | str, cycles: int, f: str, sigf: str,
- fwt: str, phwt: str, func: Callable = n_glycosylate_from_objects, verbose: bool = False) -> Tuple[
+ fwt: str, phwt: str, type: Type = Type.n_glycosylate, verbose: bool = False) -> Tuple[
gemmi.Structure, gemmi.Mtz, dict, dict]:
"""
:param structure: The input structure file in gemmi.Structure, Path, or str format.
@@ -20,7 +51,7 @@ def glycosylate(structure: gemmi.Structure | Path | str, mtz: gemmi.Mtz | Path |
:param sigf: The column label for the structure factor uncertainties.
:param fwt: The column label for the structure factor amplitude weights (potentially None).
:param phwt: The column label for the structure factor phase weights (potentially None).
- :param func: The function to use for glycosylation. Default is n_glycosylate_from_objects.
+ :param type: The type of glycosylation to perform. Default is n_glycosylate.
:param verbose: Flag specifying whether to print verbose output. Default is False.
:return: A tuple containing the glycosylated structure in gemmi.Structure format,
the glycosylated MTZ file in gemmi.Mtz format, the log as a string, and a dictionary of snfgs.
@@ -28,6 +59,8 @@ def glycosylate(structure: gemmi.Structure | Path | str, mtz: gemmi.Mtz | Path |
sails_structure = interface.get_sails_structure(structure)
sails_mtz = interface.get_sails_mtz(mtz, f, sigf, fwt, phwt)
resource = importlib.resources.files('sails').joinpath("data")
+
+ func = map_type_to_function(type)
result = func(sails_structure, sails_mtz, cycles, str(resource), verbose)
return (interface.extract_sails_structure(result.structure), interface.extract_sails_mtz(result.mtz),
@@ -87,9 +120,8 @@ def run_cli():
labels = get_column_labels(args.colin_fo, args.colin_fwt)
- func = c_glycosylate_from_objects if args.cglycan else n_glycosylate_from_objects
- cycles = 1 if args.cglycan else args.cycles
- structure, mtz, log, snfgs = glycosylate(args.pdbin, args.mtzin, cycles, *labels, func, args.v)
+ cycles = args.cycles if args.type == Type.n_glycosylate else 1
+ structure, mtz, log, snfgs = glycosylate(args.pdbin, args.mtzin, cycles, *labels, args.type, args.v)
if args.snfgout:
save_snfgs(snfgs, Path(args.snfgout))
@@ -115,8 +147,7 @@ def parse_args():
parser.add_argument("-colin-fo", type=str, required=False, default="FP,SIGFP")
parser.add_argument("-colin-fwt", type=str, required=False, default="")
parser.add_argument("-cycles", type=int, required=False, default=2)
- parser.add_argument("-nglycan", action=argparse.BooleanOptionalAction)
- parser.add_argument("-cglycan", action=argparse.BooleanOptionalAction)
+ parser.add_argument("-type", type=Type.from_string, choices=list(Type), default=Type.n_glycosylate)
parser.add_argument("-v", action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--version", action="version", version=__version__)
diff --git a/package/tests/test_glycosylation.py b/package/tests/test_glycosylation.py
index d88f2f4..e5210ee 100644
--- a/package/tests/test_glycosylation.py
+++ b/package/tests/test_glycosylation.py
@@ -19,7 +19,7 @@ def cglycan(data_base_path):
s = gemmi.read_structure(str(s_path))
m = gemmi.read_mtz_file(str(m_path))
- return s, m, 1, "FP", "SIGFP", "", "", sails.c_glycosylate_from_objects
+ return s, m, 1, "FP", "SIGFP", "", "", sails.Type.c_glycosylate
def test_cglycosylation(cglycan):