-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseR_ML_AOA.js
More file actions
276 lines (249 loc) · 11.5 KB
/
useR_ML_AOA.js
File metadata and controls
276 lines (249 loc) · 11.5 KB
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/**
* @constant {module} R R package to execute R Files, commands and methods
*/
const R = require('r-integration');
/**
* @constant {String} rFilePath Path to the R File where the functions are stored
*/
const rFilePath = './R/ML_AOA.R';
/**
* The function calls the classifyAndAOA function of the ML_AOA-R-script. It passes the path of the model
* to be used for the calculations and the desired bands which the AOI-stack bands should be named like.
* The function returns the output variable in which the reponse of the asyncronous call is stored.
* The response is either a String which confirms the successfull calculations or an error.
*
* @async
* @param {String} modelPath The relative path to the location of the model which the user provided.
* @param {String[]} desiredBands Telling the R-Skript how to name the bands of the used aoi.tif. Each Band must be a standalone String in
* the Array. Required is the 'SCL' which was used for filtering the clouds before.
* @returns the result of the R-Skript. Either error object or String that confirms the successfull calculations.
*/
async function calculateAOAwithGivenModel(modelPath, desiredBands, additionalIndices) {
let output = {};
output.training = ["3"]
try {
output.classifyAndAOA = await R.callMethodAsync(rFilePath, "classifyAndAOA", { modelPath: modelPath, desiredBands: desiredBands, additionalIndices: additionalIndices })
} catch (error) {
output.classifyAndAOA = ["2"]
}
return output;
}
/**
* The function calls the training function of the ML_AOA-R-script. It passes the algorithm (desired by the user),
* the trainingdataPath (relative filepath where the uploaded training data can be found), the hyperparameter (defined by the user)
* and the desiredBands (to name the aoi.tif bands). The function returns an output object in which the responses of the async calls
* are stored. If an unexpected error occurs the output variable is set to a specific value.
*
* @async
* @param {String} algorithm Abreviation of the method in caret package to tell the Skript the how to train.
* @param {String} trainingDataPath The relative path to the location of the training data which the user provided.
* @param {Numbers[]} hyperparameter Hyperparameter selected by the user or default values
* @param {Array} desiredBands Telling the R-Skript how to name the bands of the used trainingData.tif and aoi.tif. Each Band must be a standalone String in
* the Array. Required is the 'SCL' which was used for filtering the clouds before.
* @returns
*/
async function calculateNewModelAndAOA(algorithm, trainingDataPath, hyperparameter, desiredBands, additionalIndices) {
let output = {}
try {
output.training = await R.callMethodAsync(rFilePath, "training", { algorithm: algorithm, trainingDataPath: trainingDataPath, hyperparameter: hyperparameter, desiredBands: desiredBands, additionalIndices: additionalIndices })
} catch (error) {
output.training = ["2"]
output.classifyAndAOA = ["3"]
return output;
}
try {
output.classifyAndAOA = await R.callMethodAsync(rFilePath, "classifyAndAOA", { modelPath: "R/model/model.RDS", desiredBands: desiredBands, additionalIndices: additionalIndices })
} catch (error) {
output.classifyAndAOA = ["2"]
}
console.log("output: ", output)
return output;
}
/**
* This function will process the incoming data in the format which is needed by the R function. If the request of the user is based on
* an uploaded model, only three parameters (option, filePath, desiredBands) are needed. If it is based on training data,
* five parameters (option, filePath, desiredBands, algorithm, trainingData) are necessary.
* @param {{
* whereareyoufrom: String,
* topleftlat: Number,
* topleftlng: Number,
* bottomleftlat: Number,
* bottomleftlng: Number,
* bottomrightlat: Number,
* bottomrightlng: Number,
* toprightlat: Number,
* toprightlng: Number,
* option: String,
* algorithm: String,
* startDate: Date-String,
* endDate: Date-String;
* filename: String,
* resolution: String,
* channels: String[],
* coverage: Number,
* mtry: String
* }} data The data which must be provided by the POST request, to start the R function.
* @returns The processed data as an object.
*/
function processInputData(data) {
var out = {
option: data.option,
filePath: './public/uploads/' + data.filename,
desiredBands: data.channels,
additionalIndices: data.additionalIndices
}
if (data.option == 'data') {
if (data.algorithm == "rf") {
out.algorithm = "rf";
out.hyperparameter = [data.mtry]
} else if (data.algorithm == "svmRadial") {
out.algorithm = "svmRadial"
out.hyperparameter = [data.sigma, data.cost]
}
}
out.additionalIndices.push('')
return out;
}
/**
* The function gets the metadata from the users request and processes it first for its further calculations. Onwards either the function for calculating
* the prediction and aoa with a given model is called or the function which first calculates a model based on provided training data and afterwards calculates
* the prediction and aoa is called.
* @async
* @param {{
* whereareyoufrom: String,
* topleftlat: Number,
* topleftlng: Number,
* bottomleftlat: Number,
* bottomleftlng: Number,
* bottomrightlat: Number,
* bottomrightlng: Number,
* toprightlat: Number,
* toprightlng: Number,
* option: String,
* algorithm: String,
* startDate: Date-String,
* endDate: Date-String;
* filename: String,
* resolution: String,
* channels: String[],
* coverage: Number,
* mtry: String
* }} request All the data which will be provided from the front end.
* @returns The output which is generated by getTraingDataTif
*/
async function calculateAOA(data) {
let processedData = processInputData(data);
let output = {}
if (processedData.option == 'data') {
output = await calculateNewModelAndAOA(processedData.algorithm, processedData.filePath, processedData.hyperparameter, processedData.desiredBands, processedData.additionalIndices)
if (output.training[0] === "0" && output.classifyAndAOA[0] === '0') {
output.training = {
status: 'ok',
data: 'Model training: Successfull'
}
output.classifyAndAOA = {
status: 'ok',
data: 'Prediction and AOA: Successfull'
}
console.log("model.RDS was successfully created")
console.log("prediction.tif was successfully created")
console.log("aoa.tif was successfully created")
} else if (output.training[0] === '2' && output.classifyAndAOA[0] === '3') {
output.training = {
status: 'error',
error: 'Model training: Unexpected error occured',
errorDetails: output.training[0]
}
output.classifyAndAOA = {
status: 'not executed',
error: 'Prediction and AOA: Not executed due to unexpected error in model training',
errorDetails: output.classifyAndAOA[0]
}
console.log("Model training: Unexpected error occured")
} else if (output.training[0] === '0' && output.classifyAndAOA[0] === '2') {
output.training = {
status: 'ok',
data: 'Model training: Successfull'
}
output.classifyAndAOA = {
status: 'error',
error: 'Prediction and AOA: Unexpected error occured',
errorDetails: output.classifyAndAOA[0]
}
console.log("Prediction and AOA: Unexpected error occured")
}
//Setting output.status to 'ok' if the script(s) run successfully, otherwise 'error'.
if (output.training.status === 'ok' && output.classifyAndAOA.status === 'ok') {
output.status = 'ok'
} else {
output.status = 'error'
}
} else if (processedData.option == 'model') {
output = await calculateAOAwithGivenModel(processedData.filePath, processedData.desiredBands, processedData.additionalIndices)
if (output.training[0] === '3' && output.classifyAndAOA[0] === '0') {
output.training = {
status: 'not executed',
error: 'Model training: Not executed due to calculation with uploaded model',
errorDetails: output.training[0]
}
output.classifyAndAOA = {
status: 'ok',
data: 'Prediction and AOA: Successfull'
}
console.log("prediction.tif was successfully created")
console.log("aoa.tif was successfully created")
} else if (output.training[0] === '3' && output.classifyAndAOA[0] === '1') {
output.training = {
status: 'not executed',
error: 'Model training: Not executed due to calculation with uploaded model',
errorDetails: output.training[0]
}
output.classifyAndAOA = {
status: 'error',
error: 'Prediction and AOA: There are predictors in the uploaded model which are are missing in the Sentinel data',
errorDetails: output.classifyAndAOA[0]
}
console.log("Prediction and AOA: There are predictors in the uploaded model which are are missing in the Sentinel data")
} else if (output.training[0] === '3' && output.classifyAndAOA[0] === '2') {
output.training = {
status: 'not executed',
error: 'Model training: Not executed due to calculation with uploaded model',
errorDetails: output.training[0]
}
output.classifyAndAOA = {
status: 'error',
error: 'Prediction and AOA: Unexpected error occured',
errorDetails: output.classifyAndAOA[0]
}
console.log("Prediction and AOA: Unexpected error occured")
} else if (output.training[0] === '3' && output.classifyAndAOA[0] === '4') {
output.training = {
status: 'not executed',
error: 'Model training: Not executed due to calculation with uploaded model',
errorDetails: output.training[0]
}
output.classifyAndAOA = {
status: 'error',
error: 'Prediction and AOA: Model type is not supported. Use model of type "rf" or "svmRadial',
errorDetails: output.classifyAndAOA[0]
}
console.log("Prediction and AOA: Unexpected error occured")
}
//Setting output.status to 'ok' if the script(s) run successfully, otherwise 'error'.
if (output.classifyAndAOA.status === 'ok') {
output.status = 'ok'
} else {
output.status = 'error'
}
}
return output;
}
/** error-codes
* 0: ok
* 1: predictor of model not in the given sentinel tif (only relevant if working with user model)
* 2: unexpected error
* 3: not executed
*/
module.exports = {
calculateAOA, calculateAOAwithGivenModel, calculateNewModelAndAOA, processInputData
};