gorder/
errors.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Released under MIT License.
// Copyright (c) 2024 Ladislav Bartos

//! This module contains error types that can be returned by the `gorder` crate.

use std::path::Path;

use colored::{ColoredString, Colorize};
use groan_rs::errors::SelectError;
use thiserror::Error;

fn path_to_yellow(path: &Path) -> ColoredString {
    path.to_str().unwrap().yellow()
}

/// Errors that can occur when creating a `GridSpan` structure.
#[derive(Error, Debug)]
pub enum GridSpanError {
    #[error("{} the first coordinate for the grid span ('{}' nm) is higher than the second coordinate for the grid span ('{}' nm)", "error:".red().bold(), .0.to_string().yellow(), .1.to_string().yellow())]
    Invalid(f32, f32),
}

/// Errors that can occur when analyzing system topology.
#[derive(Error, Debug)]
pub enum TopologyError {
    #[error("{}", .0)]
    InvalidQuery(SelectError),

    #[error("{} group '{}' is empty", "error:".red().bold(), .0.yellow())]
    EmptyGroup(String),

    #[error("{} {} atoms are part of both '{}' (query: '{}') and '{}' (query: '{}')", "error:".red().bold(), .n_overlapping.to_string().yellow(), .name1.yellow(), .query1.yellow(), .name2.yellow(), .query2.yellow())]
    AtomsOverlap {
        n_overlapping: usize,
        name1: String,
        query1: String,
        name2: String,
        query2: String,
    },

    #[error("{} molecule starting with atom index '{}' contains multiple head group atoms", "error:".red().bold(), .0.to_string().yellow())]
    MultipleHeads(usize),

    #[error("{} molecule starting with atom index '{}' contains no head group atom", "error:".red().bold(), .0.to_string().yellow())]
    NoHead(usize),

    #[error("{} molecule starting with atom index '{}' contains no methyl group atom", "error:".red().bold(), .0.to_string().yellow())]
    NoMethyl(usize),

    #[error("{} molecule starting with atom index '{}' contains a number of methyl group atoms ('{}') not consistent with other molecules ('{}')", "error:".red().bold(), .0.to_string().yellow(), .1.to_string().yellow(), .2.to_string().yellow())]
    InconsistentNumberOfMethyls(usize, usize, usize),

    #[error("{} system has undefined simulation box", "error:".red().bold())]
    UndefinedBox,

    #[error("{} the simulation box is not orthogonal", "error:".red().bold())]
    NotOrthogonalBox,

    #[error("{} all dimensions of the simulation box are zero", "error:".red().bold())]
    ZeroBox,

    #[error("{}", .0)]
    OrderMapError(OrderMapConfigError),
}

/// Errors that can occur while analyzing the trajectory.
#[derive(Error, Debug)]
pub enum AnalysisError {
    #[error("{} system has undefined simulation box", "error:".red().bold())]
    UndefinedBox,

    #[error("{} the simulation box is not orthogonal", "error:".red().bold())]
    NotOrthogonalBox,

    #[error("{} all dimensions of the simulation box are zero", "error:".red().bold())]
    ZeroBox,

    #[error("{} atom with atom index '{}' has an undefined position", "error:".red().bold(), .0.to_string().yellow())]
    UndefinedPosition(usize),

    #[error("{} could not calculate global membrane center", "error:".red().bold())]
    InvalidGlobalMembraneCenter,

    #[error("{} could not calculate local membrane center for molecule with a head identifier index '{}'", "error:".red().bold(), .0.to_string().yellow())]
    InvalidLocalMembraneCenter(usize),
}

/// Errors that can occur while writing the results.
#[derive(Error, Debug)]
pub enum WriteError {
    #[error("{} could not create file '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotCreateFile(Box<Path>),

    #[error("{} could not create a backup for file '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotBackupFile(Box<Path>),

    #[error("{} could not write output file header into '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotWriteHeader(Box<Path>),

    #[error("{} could not write results in yaml format into '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotWriteYaml(Box<Path>),

    #[error("{} could not write results in the output file ({})", "error:".red().bold(), .0)]
    CouldNotWriteResults(std::io::Error),
}

/// Errors that can occur while writing the order maps.
#[derive(Error, Debug)]
pub enum OrderMapWriteError {
    #[error("{} could not create directory '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotCreateDirectory(Box<Path>),

    #[error("{} could not create a backup for directory '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotBackupDirectory(Box<Path>),

    #[error("{} could not remove an existing directory '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotRemoveDirectory(Box<Path>),

    #[error("{} could not create file '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotCreateFile(Box<Path>),

    #[error("{} could not write line into '{}'", "error:".red().bold(), path_to_yellow(.0))]
    CouldNotWriteLine(Box<Path>),
}

/// Errors that can occur when constructing an `Analysis` structure from the provided configuration.
#[derive(Error, Debug)]
pub enum ConfigError {
    #[error("{} could not open the configuration file '{}'", "error:".red().bold(), .0.yellow())]
    CouldNotOpenConfig(String),
    #[error("{} could not understand the contents of the configuration file '{}' ({})", "error:".red().bold(), .0.yellow(), .1)]
    CouldNotParseConfig(String, serde_yaml::Error),
    #[error("{} the specified value of '{}' is invalid (must be positive)", "error:".red().bold(), "step".yellow())]
    InvalidStep,
    #[error("{} the specified value of '{}' is invalid (must be positive)", "error:".red().bold(), "min_samples".yellow())]
    InvalidMinSamples,
    #[error("{} the specified value of '{}' is invalid (must be positive)", "error:".red().bold(), "n_threads".yellow())]
    InvalidNThreads,
    #[error("{} invalid values of '{}' and '{}' (begin is higher than end)",
            "error:".red().bold(),
            "begin".yellow(),
            "end".yellow())]
    InvalidBeginEnd,
    #[error("{}", .0)]
    InvalidOrderMap(OrderMapConfigError),
}

/// Errors that can occur when constructing an `OrderMap` structure from the provided configuration.
#[derive(Error, Debug)]
pub enum OrderMapConfigError {
    #[error("{} the specified value of '{}' inside '{}' is invalid (must be positive)", 
            "error:".red().bold(), 
            "min_samples".yellow(), 
            "ordermap".yellow())]
    InvalidMinSamples,
    #[error("{} invalid span of '{}': minimum ('{}') is higher than maximum ('{}')",
            "error:".red().bold(),
            "ordermap".yellow(),
            .0.to_string().yellow(), .1.to_string().yellow())]
    InvalidGridSpan(f32, f32),
    #[error("{} invalid bin size of '{}': value is '{}', must be positive", 
            "error:".red().bold(), 
            "ordermap".yellow(), 
            .0.to_string().yellow())]
    InvalidBinSize(f32),
    #[error("{} invalid bin size of '{}': bin size of '{}x{}' is larger than grid span of '{}x{}'",
            "error:".red().bold(),
            "ordermap".yellow(),
            .0.0.to_string().yellow(),
            .0.1.to_string().yellow(),
            .1.0.to_string().yellow(),
            .1.1.to_string().yellow())]
    BinTooLarge((f32, f32), (f32, f32)),
}