@dnv-plant/typescriptpws 1.0.27 → 1.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2544 @@
1
+ /***********************************************************************
2
+ * This file has been auto-generated by a code generation tool.
3
+ * Version: 1.0.38
4
+ * Date/time: 24 Mar 2025 16:46:20
5
+ * Template: templates/typescriptpws/calculations.razor.
6
+ ***********************************************************************/
7
+
8
+
9
+
10
+ import * as Enums from "../enums";
11
+ import * as Entities from "../entities";
12
+ import * as EntitySchemas from "../entity-schemas";
13
+ import { getAnalyticsApiTarget, getClientAliasId, postRequest } from "../utilities";
14
+
15
+ import Joi from "joi";
16
+ import { AxiosResponse } from "axios";
17
+
18
+
19
+ class CalculationRequestBase {
20
+ /**
21
+ * Calculation request base class.
22
+ */
23
+ constructor() {
24
+ // Base class initialization code
25
+ }
26
+ }
27
+
28
+ class CalculationBase {
29
+ resultCode?: Enums.ResultCode = Enums.ResultCode.SUCCESS;
30
+ messages: string[] = [];
31
+ calculationElapsedTime?: number = 0.0;
32
+ operationId?: string = "";
33
+
34
+ /**
35
+ * Post JSON to URL and time the call
36
+ */
37
+ async postRequest(url: string, data: string): Promise<AxiosResponse> {
38
+ return postRequest(url, data);
39
+ }
40
+
41
+ /**
42
+ * Utility method to print the messages returned by the calculation.
43
+ */
44
+ printMessages(): void {
45
+ if (this.messages && this.messages.length > 0) {
46
+ this.messages.forEach((message) => console.log(message));
47
+ } else {
48
+ console.log("No messages");
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Utility method to handle a failed response.
54
+ */
55
+ handleFailedResponse(response: AxiosResponse): void {
56
+ try {
57
+ const validatedFailedResponse = new CalculationFailedResponseSchema().validate(response.data);
58
+
59
+ this.resultCode = validatedFailedResponse.resultCode;
60
+ this.messages.push(...(validatedFailedResponse.messages ?? []));
61
+ this.calculationElapsedTime = validatedFailedResponse.calculationElapsedTime;
62
+ this.operationId = validatedFailedResponse.operationId;
63
+ } catch (error) {
64
+ if (error instanceof Error) {
65
+ this.messages.push(`Failed to parse response: ${error.message}`);
66
+ } else {
67
+ this.messages.push("An unknown error occurred during response parsing.");
68
+ }
69
+ console.error("Failed to parse response:", error);
70
+ } finally {
71
+ this.messages.push(`${response.statusText} (Status code: ${response.status})`);
72
+ }
73
+ }
74
+ }
75
+
76
+ class CalculationResponseBase {
77
+ resultCode?: Enums.ResultCode;
78
+ messages?: string[];
79
+ calculationElapsedTime?: number;
80
+ operationId?: string;
81
+
82
+ /**
83
+ * Calculation response base class.
84
+ */
85
+ constructor(
86
+ resultCode?: Enums.ResultCode,
87
+ messages?: string[],
88
+ calculationElapsedTime?: number,
89
+ operationId?: string
90
+ ) {
91
+ this.resultCode = resultCode;
92
+ this.messages = messages;
93
+ this.calculationElapsedTime = calculationElapsedTime;
94
+ this.operationId = operationId;
95
+ }
96
+ }
97
+
98
+ class CalculationFailedResponse extends CalculationResponseBase {
99
+ /**
100
+ * Calculation failed response class.
101
+ */
102
+ constructor(
103
+ resultCode?: Enums.ResultCode,
104
+ messages: string[] = [],
105
+ calculationElapsedTime: number = 0,
106
+ operationId: string = ""
107
+ ) {
108
+ super(resultCode, messages, calculationElapsedTime, operationId);
109
+ }
110
+ }
111
+
112
+ class CalculationFailedResponseSchema {
113
+ schema: Joi.ObjectSchema;
114
+
115
+ /**
116
+ * Calculation failed response schema.
117
+ */
118
+ constructor() {
119
+ this.schema = Joi.object({
120
+ resultCode: Joi.string()
121
+ .valid(...Object.values(Enums.ResultCode))
122
+ .required(),
123
+ messages: Joi.array().items(Joi.string()).required(),
124
+ calculationElapsedTime: Joi.number().required(),
125
+ operationId: Joi.string().required(),
126
+ }).unknown(true);
127
+ }
128
+
129
+ validate(data: {
130
+ resultCode: Enums.ResultCode;
131
+ messages: string[];
132
+ calculationElapsedTime: number;
133
+ operationId: string;
134
+ }) {
135
+ const { error, value } = this.schema.validate(data);
136
+ if (error) throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
137
+ return this.makeCalculationFailedResponse(value);
138
+ }
139
+
140
+ makeCalculationFailedResponse(data: {
141
+ resultCode: Enums.ResultCode;
142
+ messages: string[];
143
+ calculationElapsedTime: number;
144
+ operationId: string;
145
+ }) {
146
+ return new CalculationFailedResponse(data.resultCode, data.messages, data.calculationElapsedTime, data.operationId);
147
+ }
148
+ }
149
+
150
+ export interface ConcentrationAtPointCalculationRequestSchemaData {
151
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
152
+ weather: Entities.Weather;
153
+ dispersionRecords: Entities.DispersionRecord[];
154
+ dispersionRecordCount: number;
155
+ substrate: Entities.Substrate;
156
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
157
+ material: Entities.Material;
158
+ dispersionParameters: Entities.DispersionParameters;
159
+ }
160
+
161
+ class ConcentrationAtPointCalculationRequest extends CalculationRequestBase {
162
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
163
+ weather: Entities.Weather;
164
+ dispersionRecords: Entities.DispersionRecord[];
165
+ dispersionRecordCount: number;
166
+ substrate: Entities.Substrate;
167
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
168
+ material: Entities.Material;
169
+ dispersionParameters: Entities.DispersionParameters;
170
+
171
+ /**
172
+ * ConcentrationAtPoint calculation request class.
173
+ *
174
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
175
+ * @param {Entities.Weather} weather - A Weather entity.
176
+ * @param {Entities.DispersionRecord[]} dispersionRecords - Array of Dispersion Record.
177
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
178
+ * @param {Entities.Substrate} substrate - A Substrate entity.
179
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
180
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
181
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
182
+ */
183
+ constructor(
184
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
185
+ weather: Entities.Weather,
186
+ dispersionRecords: Entities.DispersionRecord[],
187
+ dispersionRecordCount: number,
188
+ substrate: Entities.Substrate,
189
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
190
+ material: Entities.Material,
191
+ dispersionParameters: Entities.DispersionParameters
192
+ ) {
193
+ super();
194
+ this.scalarUdmOutputs = scalarUdmOutputs;
195
+ this.weather = weather;
196
+ this.dispersionRecords = dispersionRecords;
197
+ this.dispersionRecordCount = dispersionRecordCount;
198
+ this.substrate = substrate;
199
+ this.dispersionOutputConfig = dispersionOutputConfig;
200
+ this.material = material;
201
+ this.dispersionParameters = dispersionParameters;
202
+ }
203
+ }
204
+
205
+ export class ConcentrationAtPointCalculationRequestSchema {
206
+ schema: Joi.ObjectSchema;
207
+ propertyTypes: Record<string, string>;
208
+
209
+ /**
210
+ * Schema for the ConcentrationAtPoint calculation request.
211
+ */
212
+ constructor() {
213
+ this.schema = Joi.object({
214
+ scalarUdmOutputs: new EntitySchemas.ScalarUdmOutputsSchema().schema,
215
+ weather: new EntitySchemas.WeatherSchema().schema,
216
+ dispersionRecords: Joi.array().items(new EntitySchemas.DispersionRecordSchema().schema).allow(null),
217
+ dispersionRecordCount: Joi.number().integer(),
218
+ substrate: new EntitySchemas.SubstrateSchema().schema,
219
+ dispersionOutputConfig: new EntitySchemas.DispersionOutputConfigSchema().schema,
220
+ material: new EntitySchemas.MaterialSchema().schema,
221
+ dispersionParameters: new EntitySchemas.DispersionParametersSchema().schema,
222
+ }).unknown(true);
223
+
224
+ this.propertyTypes = {
225
+ scalarUdmOutputs: "Entities.ScalarUdmOutputs",
226
+ weather: "Entities.Weather",
227
+ dispersionRecords: "Entities.DispersionRecord[]",
228
+ dispersionRecordCount: "number",
229
+ substrate: "Entities.Substrate",
230
+ dispersionOutputConfig: "Entities.DispersionOutputConfig",
231
+ material: "Entities.Material",
232
+ dispersionParameters: "Entities.DispersionParameters",
233
+ };
234
+ }
235
+
236
+ validate(data: ConcentrationAtPointCalculationRequestSchemaData): ConcentrationAtPointCalculationRequest {
237
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
238
+ if (error) {
239
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
240
+ }
241
+ return this.makeCalculationRequest(value);
242
+ }
243
+
244
+ makeCalculationRequest(data: ConcentrationAtPointCalculationRequestSchemaData): ConcentrationAtPointCalculationRequest {
245
+ return new ConcentrationAtPointCalculationRequest(
246
+ data.scalarUdmOutputs,
247
+ data.weather,
248
+ data.dispersionRecords,
249
+ data.dispersionRecordCount,
250
+ data.substrate,
251
+ data.dispersionOutputConfig,
252
+ data.material,
253
+ data.dispersionParameters
254
+ );
255
+ }
256
+ }
257
+
258
+ export class ConcentrationAtPointCalculation extends CalculationBase {
259
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
260
+ weather: Entities.Weather;
261
+ dispersionRecords: Entities.DispersionRecord[];
262
+ dispersionRecordCount: number;
263
+ substrate: Entities.Substrate;
264
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
265
+ material: Entities.Material;
266
+ dispersionParameters: Entities.DispersionParameters;
267
+ concentration?: number;
268
+
269
+ /**
270
+ * Calculates the concentration at a particular distance downwind and crosswind position at the current effect height and averaging time.
271
+ *
272
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
273
+ * @param {Entities.Weather} weather - A Weather entity.
274
+ * @param {Entities.DispersionRecord[]} dispersionRecords - Array of Dispersion Record.
275
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
276
+ * @param {Entities.Substrate} substrate - A Substrate entity.
277
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
278
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
279
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
280
+ */
281
+ constructor(
282
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
283
+ weather: Entities.Weather,
284
+ dispersionRecords: Entities.DispersionRecord[],
285
+ dispersionRecordCount: number,
286
+ substrate: Entities.Substrate,
287
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
288
+ material: Entities.Material,
289
+ dispersionParameters: Entities.DispersionParameters
290
+ ) {
291
+ super();
292
+ this.scalarUdmOutputs = scalarUdmOutputs;
293
+ this.weather = weather;
294
+ this.dispersionRecords = dispersionRecords;
295
+ this.dispersionRecordCount = dispersionRecordCount;
296
+ this.substrate = substrate;
297
+ this.dispersionOutputConfig = dispersionOutputConfig;
298
+ this.material = material;
299
+ this.dispersionParameters = dispersionParameters;
300
+ }
301
+
302
+ async run() {
303
+ try {
304
+ const request = new ConcentrationAtPointCalculationRequest(
305
+ this.scalarUdmOutputs,
306
+ this.weather,
307
+ this.dispersionRecords,
308
+ this.dispersionRecordCount,
309
+ this.substrate,
310
+ this.dispersionOutputConfig,
311
+ this.material,
312
+ this.dispersionParameters
313
+ );
314
+
315
+ const schema = new ConcentrationAtPointCalculationRequestSchema();
316
+ const validatedRequest = schema.validate(request);
317
+
318
+ const requestJson = JSON.stringify(validatedRequest);
319
+ const url = `${getAnalyticsApiTarget()}calculateconcentrationatpoint?clientId=${getClientAliasId()}`;
320
+
321
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
322
+
323
+ const response = await this.postRequest(url, requestJson);
324
+
325
+ if (response.status >= 200 && response.status < 300) {
326
+ const schema = new ConcentrationAtPointCalculationResponseSchema();
327
+ const validatedResponse = schema.validate(response.data);
328
+
329
+ this.resultCode = validatedResponse.resultCode;
330
+ if (this.resultCode === Enums.ResultCode.SUCCESS) {
331
+ this.concentration = validatedResponse.concentration;
332
+ this.resultCode = validatedResponse.resultCode;
333
+ this.messages = validatedResponse.messages ?? [];
334
+ this.calculationElapsedTime = validatedResponse.calculationElapsedTime;
335
+ this.operationId = validatedResponse.operationId;
336
+ } else {
337
+ this.messages.push(...(validatedResponse.messages ?? []));
338
+ }
339
+ } else {
340
+ this.handleFailedResponse(response);
341
+ }
342
+ } catch (error) {
343
+ if (error instanceof Error) {
344
+ this.messages.push(`Error: ${error.message}`);
345
+ } else {
346
+ this.messages.push(`Unexpected error: ${JSON.stringify(error)}`);
347
+ }
348
+ console.error(error);
349
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
350
+ }
351
+
352
+ return this.resultCode;
353
+ }
354
+
355
+ toString() {
356
+ const parts = ["* ConcentrationAtPoint"];
357
+
358
+ parts.push(`concentration: ${String(this.concentration)}`);
359
+ parts.push(`resultCode: ${String(this.resultCode)}`);
360
+ parts.push("*** messages:");
361
+ parts.push(`messages: ${this.messages !== undefined ? this.messages : "(None)"}`);
362
+ parts.push(`calculationElapsedTime: ${this.calculationElapsedTime !== undefined ? this.calculationElapsedTime : "(None)"}`);
363
+ parts.push(`operationId: ${this.operationId !== undefined ? this.operationId : "(None)"}`);
364
+
365
+ return parts.join("\n");
366
+ }
367
+ }
368
+
369
+ export class ConcentrationAtPointCalculationResponse extends CalculationResponseBase {
370
+ concentration: number;
371
+
372
+ /**
373
+ * ConcentrationAtPoint calculation response class.
374
+ *
375
+ * @param {number} concentration - Concentration at a position of interest.
376
+ */
377
+ constructor(
378
+ concentration: number,
379
+ resultCode: Enums.ResultCode,
380
+ messages: string[],
381
+ calculationElapsedTime: number,
382
+ operationId: string
383
+ ) {
384
+ super();
385
+ this.concentration = concentration;
386
+ this.resultCode = resultCode;
387
+ this.messages = messages;
388
+ this.calculationElapsedTime = calculationElapsedTime;
389
+ this.operationId = operationId;
390
+ }
391
+
392
+ initialiseFromDictionary(data: { [key: string]: unknown }) {
393
+ if (data.concentration !== undefined && typeof data.concentration === "number") {
394
+ this.concentration = data.concentration as number;
395
+ }
396
+ if (data.resultCode !== undefined && (typeof data.resultCode === "string" || typeof data.resultCode === "number")) {
397
+ this.resultCode = data.resultCode as Enums.ResultCode;
398
+ }
399
+ this.messages = this.messages ?? [];
400
+ if (data.messages && Array.isArray(data.messages)) {
401
+ this.messages.push(...data.messages);
402
+ }
403
+ if (data.calculationElapsedTime !== undefined && typeof data.calculationElapsedTime === "number") {
404
+ this.calculationElapsedTime = data.calculationElapsedTime as number;
405
+ }
406
+ if (data.operationId !== undefined && typeof data.operationId === "string") {
407
+ this.operationId = data.operationId as string;
408
+ }
409
+ }
410
+ }
411
+
412
+ export interface ConcentrationAtPointCalculationResponseSchemaData {
413
+ concentration: number;
414
+ resultCode: Enums.ResultCode;
415
+ messages: string[];
416
+ calculationElapsedTime: number;
417
+ operationId: string;
418
+ }
419
+
420
+ export class ConcentrationAtPointCalculationResponseSchema {
421
+ schema: Joi.ObjectSchema;
422
+ propertyTypes: Record<string, string>;
423
+
424
+ /**
425
+ * Schema for the ConcentrationAtPoint calculation response.
426
+ */
427
+ constructor() {
428
+ this.schema = Joi.object({
429
+ concentration: Joi.number().unsafe(),
430
+ resultCode: Joi.string().valid(...Object.values(Enums.ResultCode)),
431
+ messages: Joi.array().items(Joi.string()),
432
+ calculationElapsedTime: Joi.number().unsafe(),
433
+ operationId: Joi.string().uuid().allow(null),
434
+ }).unknown(true);
435
+
436
+ this.propertyTypes = {
437
+ concentration: "number",
438
+ };
439
+ }
440
+
441
+ validate(data: ConcentrationAtPointCalculationResponseSchemaData): ConcentrationAtPointCalculationResponse {
442
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
443
+ if (error) {
444
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
445
+ }
446
+ return this.makeCalculationResponse(value);
447
+ }
448
+
449
+ makeCalculationResponse(data: ConcentrationAtPointCalculationResponseSchemaData): ConcentrationAtPointCalculationResponse {
450
+ return new ConcentrationAtPointCalculationResponse(
451
+ data.concentration,
452
+ data.resultCode,
453
+ data.messages,
454
+ data.calculationElapsedTime,
455
+ data.operationId
456
+ );
457
+ }
458
+ }
459
+
460
+ export interface DistancesAndFootprintsToConcentrationLevelsCalculationRequestSchemaData {
461
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
462
+ weather: Entities.Weather;
463
+ dispersionRecords: Entities.DispersionRecord[];
464
+ dispersionRecordCount: number;
465
+ substrate: Entities.Substrate;
466
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[];
467
+ dispersionOutputConfigCount: number;
468
+ dispersionParameters: Entities.DispersionParameters;
469
+ material: Entities.Material;
470
+ }
471
+
472
+ class DistancesAndFootprintsToConcentrationLevelsCalculationRequest extends CalculationRequestBase {
473
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
474
+ weather: Entities.Weather;
475
+ dispersionRecords: Entities.DispersionRecord[];
476
+ dispersionRecordCount: number;
477
+ substrate: Entities.Substrate;
478
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[];
479
+ dispersionOutputConfigCount: number;
480
+ dispersionParameters: Entities.DispersionParameters;
481
+ material: Entities.Material;
482
+
483
+ /**
484
+ * DistancesAndFootprintsToConcentrationLevels calculation request class.
485
+ *
486
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
487
+ * @param {Entities.Weather} weather - A Weather entity.
488
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
489
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
490
+ * @param {Entities.Substrate} substrate - A Substrate entity.
491
+ * @param {Entities.DispersionOutputConfig[]} dispersionOutputConfigs - An array of Dispersion Output Configs.
492
+ * @param {number} dispersionOutputConfigCount - Number of Dispersion Output Configs.
493
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
494
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
495
+ */
496
+ constructor(
497
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
498
+ weather: Entities.Weather,
499
+ dispersionRecords: Entities.DispersionRecord[],
500
+ dispersionRecordCount: number,
501
+ substrate: Entities.Substrate,
502
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[],
503
+ dispersionOutputConfigCount: number,
504
+ dispersionParameters: Entities.DispersionParameters,
505
+ material: Entities.Material
506
+ ) {
507
+ super();
508
+ this.scalarUdmOutputs = scalarUdmOutputs;
509
+ this.weather = weather;
510
+ this.dispersionRecords = dispersionRecords;
511
+ this.dispersionRecordCount = dispersionRecordCount;
512
+ this.substrate = substrate;
513
+ this.dispersionOutputConfigs = dispersionOutputConfigs;
514
+ this.dispersionOutputConfigCount = dispersionOutputConfigCount;
515
+ this.dispersionParameters = dispersionParameters;
516
+ this.material = material;
517
+ }
518
+ }
519
+
520
+ export class DistancesAndFootprintsToConcentrationLevelsCalculationRequestSchema {
521
+ schema: Joi.ObjectSchema;
522
+ propertyTypes: Record<string, string>;
523
+
524
+ /**
525
+ * Schema for the DistancesAndFootprintsToConcentrationLevels calculation request.
526
+ */
527
+ constructor() {
528
+ this.schema = Joi.object({
529
+ scalarUdmOutputs: new EntitySchemas.ScalarUdmOutputsSchema().schema,
530
+ weather: new EntitySchemas.WeatherSchema().schema,
531
+ dispersionRecords: Joi.array().items(new EntitySchemas.DispersionRecordSchema().schema).allow(null),
532
+ dispersionRecordCount: Joi.number().integer(),
533
+ substrate: new EntitySchemas.SubstrateSchema().schema,
534
+ dispersionOutputConfigs: Joi.array().items(new EntitySchemas.DispersionOutputConfigSchema().schema).allow(null),
535
+ dispersionOutputConfigCount: Joi.number().integer(),
536
+ dispersionParameters: new EntitySchemas.DispersionParametersSchema().schema,
537
+ material: new EntitySchemas.MaterialSchema().schema,
538
+ }).unknown(true);
539
+
540
+ this.propertyTypes = {
541
+ scalarUdmOutputs: "Entities.ScalarUdmOutputs",
542
+ weather: "Entities.Weather",
543
+ dispersionRecords: "Entities.DispersionRecord[]",
544
+ dispersionRecordCount: "number",
545
+ substrate: "Entities.Substrate",
546
+ dispersionOutputConfigs: "Entities.DispersionOutputConfig[]",
547
+ dispersionOutputConfigCount: "number",
548
+ dispersionParameters: "Entities.DispersionParameters",
549
+ material: "Entities.Material",
550
+ };
551
+ }
552
+
553
+ validate(data: DistancesAndFootprintsToConcentrationLevelsCalculationRequestSchemaData): DistancesAndFootprintsToConcentrationLevelsCalculationRequest {
554
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
555
+ if (error) {
556
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
557
+ }
558
+ return this.makeCalculationRequest(value);
559
+ }
560
+
561
+ makeCalculationRequest(data: DistancesAndFootprintsToConcentrationLevelsCalculationRequestSchemaData): DistancesAndFootprintsToConcentrationLevelsCalculationRequest {
562
+ return new DistancesAndFootprintsToConcentrationLevelsCalculationRequest(
563
+ data.scalarUdmOutputs,
564
+ data.weather,
565
+ data.dispersionRecords,
566
+ data.dispersionRecordCount,
567
+ data.substrate,
568
+ data.dispersionOutputConfigs,
569
+ data.dispersionOutputConfigCount,
570
+ data.dispersionParameters,
571
+ data.material
572
+ );
573
+ }
574
+ }
575
+
576
+ export class DistancesAndFootprintsToConcentrationLevelsCalculation extends CalculationBase {
577
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
578
+ weather: Entities.Weather;
579
+ dispersionRecords: Entities.DispersionRecord[];
580
+ dispersionRecordCount: number;
581
+ substrate: Entities.Substrate;
582
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[];
583
+ dispersionOutputConfigCount: number;
584
+ dispersionParameters: Entities.DispersionParameters;
585
+ material: Entities.Material;
586
+ concsUsed?: number[];
587
+ nContourPoints?: number[];
588
+ areasContour?: number[];
589
+ distancesConcentration?: number[];
590
+ contourPoints?: Entities.LocalPosition[];
591
+
592
+ /**
593
+ * Calculates the distances and maximum footprints to specified concentration of interest levels for the dispersion modelling.
594
+ *
595
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
596
+ * @param {Entities.Weather} weather - A Weather entity.
597
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
598
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
599
+ * @param {Entities.Substrate} substrate - A Substrate entity.
600
+ * @param {Entities.DispersionOutputConfig[]} dispersionOutputConfigs - An array of Dispersion Output Configs.
601
+ * @param {number} dispersionOutputConfigCount - Number of Dispersion Output Configs.
602
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
603
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
604
+ */
605
+ constructor(
606
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
607
+ weather: Entities.Weather,
608
+ dispersionRecords: Entities.DispersionRecord[],
609
+ dispersionRecordCount: number,
610
+ substrate: Entities.Substrate,
611
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[],
612
+ dispersionOutputConfigCount: number,
613
+ dispersionParameters: Entities.DispersionParameters,
614
+ material: Entities.Material
615
+ ) {
616
+ super();
617
+ this.scalarUdmOutputs = scalarUdmOutputs;
618
+ this.weather = weather;
619
+ this.dispersionRecords = dispersionRecords;
620
+ this.dispersionRecordCount = dispersionRecordCount;
621
+ this.substrate = substrate;
622
+ this.dispersionOutputConfigs = dispersionOutputConfigs;
623
+ this.dispersionOutputConfigCount = dispersionOutputConfigCount;
624
+ this.dispersionParameters = dispersionParameters;
625
+ this.material = material;
626
+ }
627
+
628
+ async run() {
629
+ try {
630
+ const request = new DistancesAndFootprintsToConcentrationLevelsCalculationRequest(
631
+ this.scalarUdmOutputs,
632
+ this.weather,
633
+ this.dispersionRecords,
634
+ this.dispersionRecordCount,
635
+ this.substrate,
636
+ this.dispersionOutputConfigs,
637
+ this.dispersionOutputConfigCount,
638
+ this.dispersionParameters,
639
+ this.material
640
+ );
641
+
642
+ const schema = new DistancesAndFootprintsToConcentrationLevelsCalculationRequestSchema();
643
+ const validatedRequest = schema.validate(request);
644
+
645
+ const requestJson = JSON.stringify(validatedRequest);
646
+ const url = `${getAnalyticsApiTarget()}calculatedistancesandfootprintstoconcentrationlevels?clientId=${getClientAliasId()}`;
647
+
648
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
649
+
650
+ const response = await this.postRequest(url, requestJson);
651
+
652
+ if (response.status >= 200 && response.status < 300) {
653
+ const schema = new DistancesAndFootprintsToConcentrationLevelsCalculationResponseSchema();
654
+ const validatedResponse = schema.validate(response.data);
655
+
656
+ this.resultCode = validatedResponse.resultCode;
657
+ if (this.resultCode === Enums.ResultCode.SUCCESS) {
658
+ this.concsUsed = validatedResponse.concsUsed;
659
+ this.nContourPoints = validatedResponse.nContourPoints;
660
+ this.areasContour = validatedResponse.areasContour;
661
+ this.distancesConcentration = validatedResponse.distancesConcentration;
662
+ this.contourPoints = validatedResponse.contourPoints;
663
+ this.resultCode = validatedResponse.resultCode;
664
+ this.messages = validatedResponse.messages ?? [];
665
+ this.calculationElapsedTime = validatedResponse.calculationElapsedTime;
666
+ this.operationId = validatedResponse.operationId;
667
+ } else {
668
+ this.messages.push(...(validatedResponse.messages ?? []));
669
+ }
670
+ } else {
671
+ this.handleFailedResponse(response);
672
+ }
673
+ } catch (error) {
674
+ if (error instanceof Error) {
675
+ this.messages.push(`Error: ${error.message}`);
676
+ } else {
677
+ this.messages.push(`Unexpected error: ${JSON.stringify(error)}`);
678
+ }
679
+ console.error(error);
680
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
681
+ }
682
+
683
+ return this.resultCode;
684
+ }
685
+
686
+ toString() {
687
+ const parts = ["* DistancesAndFootprintsToConcentrationLevels"];
688
+
689
+ parts.push("*** concsUsed:");
690
+ parts.push(
691
+ this.concsUsed && this.concsUsed.length > 0
692
+ ? this.concsUsed.map((point) => `concsUsedElement: ${point}`).join("\n")
693
+ : "concsUsed does not contain any elements"
694
+ );
695
+ parts.push("*** nContourPoints:");
696
+ parts.push(
697
+ this.nContourPoints && this.nContourPoints.length > 0
698
+ ? this.nContourPoints.map((point) => `nContourPointsElement: ${point}`).join("\n")
699
+ : "nContourPoints does not contain any elements"
700
+ );
701
+ parts.push("*** areasContour:");
702
+ parts.push(
703
+ this.areasContour && this.areasContour.length > 0
704
+ ? this.areasContour.map((point) => `areasContourElement: ${point}`).join("\n")
705
+ : "areasContour does not contain any elements"
706
+ );
707
+ parts.push("*** distancesConcentration:");
708
+ parts.push(
709
+ this.distancesConcentration && this.distancesConcentration.length > 0
710
+ ? this.distancesConcentration.map((point) => `distancesConcentrationElement: ${point}`).join("\n")
711
+ : "distancesConcentration does not contain any elements"
712
+ );
713
+ parts.push("*** contourPoints:");
714
+ parts.push(
715
+ this.contourPoints && this.contourPoints.length > 0
716
+ ? this.contourPoints.map((point) => `contourPointsElement: ${point}`).join("\n")
717
+ : "contourPoints does not contain any elements"
718
+ );
719
+ parts.push(`resultCode: ${String(this.resultCode)}`);
720
+ parts.push("*** messages:");
721
+ parts.push(`messages: ${this.messages !== undefined ? this.messages : "(None)"}`);
722
+ parts.push(`calculationElapsedTime: ${this.calculationElapsedTime !== undefined ? this.calculationElapsedTime : "(None)"}`);
723
+ parts.push(`operationId: ${this.operationId !== undefined ? this.operationId : "(None)"}`);
724
+
725
+ return parts.join("\n");
726
+ }
727
+ }
728
+
729
+ export class DistancesAndFootprintsToConcentrationLevelsCalculationResponse extends CalculationResponseBase {
730
+ concsUsed: number[];
731
+ nContourPoints: number[];
732
+ areasContour: number[];
733
+ distancesConcentration: number[];
734
+ contourPoints: Entities.LocalPosition[];
735
+
736
+ /**
737
+ * DistancesAndFootprintsToConcentrationLevels calculation response class.
738
+ *
739
+ * @param {number[]} concsUsed - An array of concentrations of interest, corresponding to the Dispersion Output Configs.
740
+ * @param {number[]} nContourPoints - An array of the number of contour points, corresponding to the Dispersion Output Configs.
741
+ * @param {number[]} areasContour - An array of areas of footprint contours, corresponding to the Dispersion Output Configs.
742
+ * @param {number[]} distancesConcentration - An array of the maximum distances downwind, corresponding to the Dispersion Output Configs.
743
+ * @param {Entities.LocalPosition[]} contourPoints - Contour points of maximum footprints to concentration level.
744
+ */
745
+ constructor(
746
+ concsUsed: number[],
747
+ nContourPoints: number[],
748
+ areasContour: number[],
749
+ distancesConcentration: number[],
750
+ contourPoints: Entities.LocalPosition[],
751
+ resultCode: Enums.ResultCode,
752
+ messages: string[],
753
+ calculationElapsedTime: number,
754
+ operationId: string
755
+ ) {
756
+ super();
757
+ this.concsUsed = concsUsed;
758
+ this.nContourPoints = nContourPoints;
759
+ this.areasContour = areasContour;
760
+ this.distancesConcentration = distancesConcentration;
761
+ this.contourPoints = contourPoints;
762
+ this.resultCode = resultCode;
763
+ this.messages = messages;
764
+ this.calculationElapsedTime = calculationElapsedTime;
765
+ this.operationId = operationId;
766
+ }
767
+
768
+ initialiseFromDictionary(data: { [key: string]: unknown }) {
769
+ if (data.concsUsed && Array.isArray(data.concsUsed)) {
770
+ this.concsUsed = data.concsUsed.map((item) => parseFloat(item));
771
+ }
772
+ if (data.nContourPoints && Array.isArray(data.nContourPoints)) {
773
+ this.nContourPoints = data.nContourPoints.map((item) => parseInt(item));
774
+ }
775
+ if (data.areasContour && Array.isArray(data.areasContour)) {
776
+ this.areasContour = data.areasContour.map((item) => parseFloat(item));
777
+ }
778
+ if (data.distancesConcentration && Array.isArray(data.distancesConcentration)) {
779
+ this.distancesConcentration = data.distancesConcentration.map((item) => parseFloat(item));
780
+ }
781
+ if (data.contourPoints && Array.isArray(data.contourPoints)) {
782
+ this.contourPoints = data.contourPoints.map(
783
+ (item) => {
784
+ const record = new Entities.LocalPosition();
785
+ record.initialiseFromDictionary(item);
786
+ return record;
787
+ }
788
+ );
789
+ }
790
+ if (data.resultCode !== undefined && (typeof data.resultCode === "string" || typeof data.resultCode === "number")) {
791
+ this.resultCode = data.resultCode as Enums.ResultCode;
792
+ }
793
+ this.messages = this.messages ?? [];
794
+ if (data.messages && Array.isArray(data.messages)) {
795
+ this.messages.push(...data.messages);
796
+ }
797
+ if (data.calculationElapsedTime !== undefined && typeof data.calculationElapsedTime === "number") {
798
+ this.calculationElapsedTime = data.calculationElapsedTime as number;
799
+ }
800
+ if (data.operationId !== undefined && typeof data.operationId === "string") {
801
+ this.operationId = data.operationId as string;
802
+ }
803
+ }
804
+ }
805
+
806
+ export interface DistancesAndFootprintsToConcentrationLevelsCalculationResponseSchemaData {
807
+ concsUsed: number[];
808
+ nContourPoints: number[];
809
+ areasContour: number[];
810
+ distancesConcentration: number[];
811
+ contourPoints: Entities.LocalPosition[];
812
+ resultCode: Enums.ResultCode;
813
+ messages: string[];
814
+ calculationElapsedTime: number;
815
+ operationId: string;
816
+ }
817
+
818
+ export class DistancesAndFootprintsToConcentrationLevelsCalculationResponseSchema {
819
+ schema: Joi.ObjectSchema;
820
+ propertyTypes: Record<string, string>;
821
+
822
+ /**
823
+ * Schema for the DistancesAndFootprintsToConcentrationLevels calculation response.
824
+ */
825
+ constructor() {
826
+ this.schema = Joi.object({
827
+ concsUsed: Joi.array().items(Joi.number().unsafe()).allow(null),
828
+ nContourPoints: Joi.array().items(Joi.number().integer()).allow(null),
829
+ areasContour: Joi.array().items(Joi.number().unsafe()).allow(null),
830
+ distancesConcentration: Joi.array().items(Joi.number().unsafe()).allow(null),
831
+ contourPoints: Joi.array().items(new EntitySchemas.LocalPositionSchema().schema).allow(null),
832
+ resultCode: Joi.string().valid(...Object.values(Enums.ResultCode)),
833
+ messages: Joi.array().items(Joi.string()),
834
+ calculationElapsedTime: Joi.number().unsafe(),
835
+ operationId: Joi.string().uuid().allow(null),
836
+ }).unknown(true);
837
+
838
+ this.propertyTypes = {
839
+ concsUsed: "number[]",
840
+ nContourPoints: "number[]",
841
+ areasContour: "number[]",
842
+ distancesConcentration: "number[]",
843
+ contourPoints: "Entities.LocalPosition[]",
844
+ };
845
+ }
846
+
847
+ validate(data: DistancesAndFootprintsToConcentrationLevelsCalculationResponseSchemaData): DistancesAndFootprintsToConcentrationLevelsCalculationResponse {
848
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
849
+ if (error) {
850
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
851
+ }
852
+ return this.makeCalculationResponse(value);
853
+ }
854
+
855
+ makeCalculationResponse(data: DistancesAndFootprintsToConcentrationLevelsCalculationResponseSchemaData): DistancesAndFootprintsToConcentrationLevelsCalculationResponse {
856
+ return new DistancesAndFootprintsToConcentrationLevelsCalculationResponse(
857
+ data.concsUsed,
858
+ data.nContourPoints,
859
+ data.areasContour,
860
+ data.distancesConcentration,
861
+ data.contourPoints,
862
+ data.resultCode,
863
+ data.messages,
864
+ data.calculationElapsedTime,
865
+ data.operationId
866
+ );
867
+ }
868
+ }
869
+
870
+ export interface DistancesToConcLevelsCalculationRequestSchemaData {
871
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
872
+ weather: Entities.Weather;
873
+ dispersionRecords: Entities.DispersionRecord[];
874
+ dispersionRecordCount: number;
875
+ substrate: Entities.Substrate;
876
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[];
877
+ dispersionOutputConfigCount: number;
878
+ material: Entities.Material;
879
+ dispersionParameters: Entities.DispersionParameters;
880
+ }
881
+
882
+ class DistancesToConcLevelsCalculationRequest extends CalculationRequestBase {
883
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
884
+ weather: Entities.Weather;
885
+ dispersionRecords: Entities.DispersionRecord[];
886
+ dispersionRecordCount: number;
887
+ substrate: Entities.Substrate;
888
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[];
889
+ dispersionOutputConfigCount: number;
890
+ material: Entities.Material;
891
+ dispersionParameters: Entities.DispersionParameters;
892
+
893
+ /**
894
+ * DistancesToConcLevels calculation request class.
895
+ *
896
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
897
+ * @param {Entities.Weather} weather - A Weather entity.
898
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
899
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
900
+ * @param {Entities.Substrate} substrate - A Substrate entity.
901
+ * @param {Entities.DispersionOutputConfig[]} dispersionOutputConfigs - An Array of Dispersion Output Configs.
902
+ * @param {number} dispersionOutputConfigCount - Number of Dispersion Output Configs.
903
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
904
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
905
+ */
906
+ constructor(
907
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
908
+ weather: Entities.Weather,
909
+ dispersionRecords: Entities.DispersionRecord[],
910
+ dispersionRecordCount: number,
911
+ substrate: Entities.Substrate,
912
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[],
913
+ dispersionOutputConfigCount: number,
914
+ material: Entities.Material,
915
+ dispersionParameters: Entities.DispersionParameters
916
+ ) {
917
+ super();
918
+ this.scalarUdmOutputs = scalarUdmOutputs;
919
+ this.weather = weather;
920
+ this.dispersionRecords = dispersionRecords;
921
+ this.dispersionRecordCount = dispersionRecordCount;
922
+ this.substrate = substrate;
923
+ this.dispersionOutputConfigs = dispersionOutputConfigs;
924
+ this.dispersionOutputConfigCount = dispersionOutputConfigCount;
925
+ this.material = material;
926
+ this.dispersionParameters = dispersionParameters;
927
+ }
928
+ }
929
+
930
+ export class DistancesToConcLevelsCalculationRequestSchema {
931
+ schema: Joi.ObjectSchema;
932
+ propertyTypes: Record<string, string>;
933
+
934
+ /**
935
+ * Schema for the DistancesToConcLevels calculation request.
936
+ */
937
+ constructor() {
938
+ this.schema = Joi.object({
939
+ scalarUdmOutputs: new EntitySchemas.ScalarUdmOutputsSchema().schema,
940
+ weather: new EntitySchemas.WeatherSchema().schema,
941
+ dispersionRecords: Joi.array().items(new EntitySchemas.DispersionRecordSchema().schema).allow(null),
942
+ dispersionRecordCount: Joi.number().integer(),
943
+ substrate: new EntitySchemas.SubstrateSchema().schema,
944
+ dispersionOutputConfigs: Joi.array().items(new EntitySchemas.DispersionOutputConfigSchema().schema).allow(null),
945
+ dispersionOutputConfigCount: Joi.number().integer(),
946
+ material: new EntitySchemas.MaterialSchema().schema,
947
+ dispersionParameters: new EntitySchemas.DispersionParametersSchema().schema,
948
+ }).unknown(true);
949
+
950
+ this.propertyTypes = {
951
+ scalarUdmOutputs: "Entities.ScalarUdmOutputs",
952
+ weather: "Entities.Weather",
953
+ dispersionRecords: "Entities.DispersionRecord[]",
954
+ dispersionRecordCount: "number",
955
+ substrate: "Entities.Substrate",
956
+ dispersionOutputConfigs: "Entities.DispersionOutputConfig[]",
957
+ dispersionOutputConfigCount: "number",
958
+ material: "Entities.Material",
959
+ dispersionParameters: "Entities.DispersionParameters",
960
+ };
961
+ }
962
+
963
+ validate(data: DistancesToConcLevelsCalculationRequestSchemaData): DistancesToConcLevelsCalculationRequest {
964
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
965
+ if (error) {
966
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
967
+ }
968
+ return this.makeCalculationRequest(value);
969
+ }
970
+
971
+ makeCalculationRequest(data: DistancesToConcLevelsCalculationRequestSchemaData): DistancesToConcLevelsCalculationRequest {
972
+ return new DistancesToConcLevelsCalculationRequest(
973
+ data.scalarUdmOutputs,
974
+ data.weather,
975
+ data.dispersionRecords,
976
+ data.dispersionRecordCount,
977
+ data.substrate,
978
+ data.dispersionOutputConfigs,
979
+ data.dispersionOutputConfigCount,
980
+ data.material,
981
+ data.dispersionParameters
982
+ );
983
+ }
984
+ }
985
+
986
+ export class DistancesToConcLevelsCalculation extends CalculationBase {
987
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
988
+ weather: Entities.Weather;
989
+ dispersionRecords: Entities.DispersionRecord[];
990
+ dispersionRecordCount: number;
991
+ substrate: Entities.Substrate;
992
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[];
993
+ dispersionOutputConfigCount: number;
994
+ material: Entities.Material;
995
+ dispersionParameters: Entities.DispersionParameters;
996
+ concUsed?: number[];
997
+ distances?: number[];
998
+
999
+ /**
1000
+ * Calculates the maximum downwind distance to a number of concentration level in the direction of the wind, at the effect height and averaging time.
1001
+ *
1002
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
1003
+ * @param {Entities.Weather} weather - A Weather entity.
1004
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
1005
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
1006
+ * @param {Entities.Substrate} substrate - A Substrate entity.
1007
+ * @param {Entities.DispersionOutputConfig[]} dispersionOutputConfigs - An Array of Dispersion Output Configs.
1008
+ * @param {number} dispersionOutputConfigCount - Number of Dispersion Output Configs.
1009
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
1010
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
1011
+ */
1012
+ constructor(
1013
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
1014
+ weather: Entities.Weather,
1015
+ dispersionRecords: Entities.DispersionRecord[],
1016
+ dispersionRecordCount: number,
1017
+ substrate: Entities.Substrate,
1018
+ dispersionOutputConfigs: Entities.DispersionOutputConfig[],
1019
+ dispersionOutputConfigCount: number,
1020
+ material: Entities.Material,
1021
+ dispersionParameters: Entities.DispersionParameters
1022
+ ) {
1023
+ super();
1024
+ this.scalarUdmOutputs = scalarUdmOutputs;
1025
+ this.weather = weather;
1026
+ this.dispersionRecords = dispersionRecords;
1027
+ this.dispersionRecordCount = dispersionRecordCount;
1028
+ this.substrate = substrate;
1029
+ this.dispersionOutputConfigs = dispersionOutputConfigs;
1030
+ this.dispersionOutputConfigCount = dispersionOutputConfigCount;
1031
+ this.material = material;
1032
+ this.dispersionParameters = dispersionParameters;
1033
+ }
1034
+
1035
+ async run() {
1036
+ try {
1037
+ const request = new DistancesToConcLevelsCalculationRequest(
1038
+ this.scalarUdmOutputs,
1039
+ this.weather,
1040
+ this.dispersionRecords,
1041
+ this.dispersionRecordCount,
1042
+ this.substrate,
1043
+ this.dispersionOutputConfigs,
1044
+ this.dispersionOutputConfigCount,
1045
+ this.material,
1046
+ this.dispersionParameters
1047
+ );
1048
+
1049
+ const schema = new DistancesToConcLevelsCalculationRequestSchema();
1050
+ const validatedRequest = schema.validate(request);
1051
+
1052
+ const requestJson = JSON.stringify(validatedRequest);
1053
+ const url = `${getAnalyticsApiTarget()}calculatedistancestoconclevels?clientId=${getClientAliasId()}`;
1054
+
1055
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
1056
+
1057
+ const response = await this.postRequest(url, requestJson);
1058
+
1059
+ if (response.status >= 200 && response.status < 300) {
1060
+ const schema = new DistancesToConcLevelsCalculationResponseSchema();
1061
+ const validatedResponse = schema.validate(response.data);
1062
+
1063
+ this.resultCode = validatedResponse.resultCode;
1064
+ if (this.resultCode === Enums.ResultCode.SUCCESS) {
1065
+ this.concUsed = validatedResponse.concUsed;
1066
+ this.distances = validatedResponse.distances;
1067
+ this.resultCode = validatedResponse.resultCode;
1068
+ this.messages = validatedResponse.messages ?? [];
1069
+ this.calculationElapsedTime = validatedResponse.calculationElapsedTime;
1070
+ this.operationId = validatedResponse.operationId;
1071
+ } else {
1072
+ this.messages.push(...(validatedResponse.messages ?? []));
1073
+ }
1074
+ } else {
1075
+ this.handleFailedResponse(response);
1076
+ }
1077
+ } catch (error) {
1078
+ if (error instanceof Error) {
1079
+ this.messages.push(`Error: ${error.message}`);
1080
+ } else {
1081
+ this.messages.push(`Unexpected error: ${JSON.stringify(error)}`);
1082
+ }
1083
+ console.error(error);
1084
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
1085
+ }
1086
+
1087
+ return this.resultCode;
1088
+ }
1089
+
1090
+ toString() {
1091
+ const parts = ["* DistancesToConcLevels"];
1092
+
1093
+ parts.push("*** concUsed:");
1094
+ parts.push(
1095
+ this.concUsed && this.concUsed.length > 0
1096
+ ? this.concUsed.map((point) => `concUsedElement: ${point}`).join("\n")
1097
+ : "concUsed does not contain any elements"
1098
+ );
1099
+ parts.push("*** distances:");
1100
+ parts.push(
1101
+ this.distances && this.distances.length > 0
1102
+ ? this.distances.map((point) => `distancesElement: ${point}`).join("\n")
1103
+ : "distances does not contain any elements"
1104
+ );
1105
+ parts.push(`resultCode: ${String(this.resultCode)}`);
1106
+ parts.push("*** messages:");
1107
+ parts.push(`messages: ${this.messages !== undefined ? this.messages : "(None)"}`);
1108
+ parts.push(`calculationElapsedTime: ${this.calculationElapsedTime !== undefined ? this.calculationElapsedTime : "(None)"}`);
1109
+ parts.push(`operationId: ${this.operationId !== undefined ? this.operationId : "(None)"}`);
1110
+
1111
+ return parts.join("\n");
1112
+ }
1113
+ }
1114
+
1115
+ export class DistancesToConcLevelsCalculationResponse extends CalculationResponseBase {
1116
+ concUsed: number[];
1117
+ distances: number[];
1118
+
1119
+ /**
1120
+ * DistancesToConcLevels calculation response class.
1121
+ *
1122
+ * @param {number[]} concUsed - An array of concentrations of interest, corresponding to the Dispersion Output Configs.
1123
+ * @param {number[]} distances - An array of the distances to concentration of interest, corresponding to the Dispersion Output Configs.
1124
+ */
1125
+ constructor(
1126
+ concUsed: number[],
1127
+ distances: number[],
1128
+ resultCode: Enums.ResultCode,
1129
+ messages: string[],
1130
+ calculationElapsedTime: number,
1131
+ operationId: string
1132
+ ) {
1133
+ super();
1134
+ this.concUsed = concUsed;
1135
+ this.distances = distances;
1136
+ this.resultCode = resultCode;
1137
+ this.messages = messages;
1138
+ this.calculationElapsedTime = calculationElapsedTime;
1139
+ this.operationId = operationId;
1140
+ }
1141
+
1142
+ initialiseFromDictionary(data: { [key: string]: unknown }) {
1143
+ if (data.concUsed && Array.isArray(data.concUsed)) {
1144
+ this.concUsed = data.concUsed.map((item) => parseFloat(item));
1145
+ }
1146
+ if (data.distances && Array.isArray(data.distances)) {
1147
+ this.distances = data.distances.map((item) => parseFloat(item));
1148
+ }
1149
+ if (data.resultCode !== undefined && (typeof data.resultCode === "string" || typeof data.resultCode === "number")) {
1150
+ this.resultCode = data.resultCode as Enums.ResultCode;
1151
+ }
1152
+ this.messages = this.messages ?? [];
1153
+ if (data.messages && Array.isArray(data.messages)) {
1154
+ this.messages.push(...data.messages);
1155
+ }
1156
+ if (data.calculationElapsedTime !== undefined && typeof data.calculationElapsedTime === "number") {
1157
+ this.calculationElapsedTime = data.calculationElapsedTime as number;
1158
+ }
1159
+ if (data.operationId !== undefined && typeof data.operationId === "string") {
1160
+ this.operationId = data.operationId as string;
1161
+ }
1162
+ }
1163
+ }
1164
+
1165
+ export interface DistancesToConcLevelsCalculationResponseSchemaData {
1166
+ concUsed: number[];
1167
+ distances: number[];
1168
+ resultCode: Enums.ResultCode;
1169
+ messages: string[];
1170
+ calculationElapsedTime: number;
1171
+ operationId: string;
1172
+ }
1173
+
1174
+ export class DistancesToConcLevelsCalculationResponseSchema {
1175
+ schema: Joi.ObjectSchema;
1176
+ propertyTypes: Record<string, string>;
1177
+
1178
+ /**
1179
+ * Schema for the DistancesToConcLevels calculation response.
1180
+ */
1181
+ constructor() {
1182
+ this.schema = Joi.object({
1183
+ concUsed: Joi.array().items(Joi.number().unsafe()).allow(null),
1184
+ distances: Joi.array().items(Joi.number().unsafe()).allow(null),
1185
+ resultCode: Joi.string().valid(...Object.values(Enums.ResultCode)),
1186
+ messages: Joi.array().items(Joi.string()),
1187
+ calculationElapsedTime: Joi.number().unsafe(),
1188
+ operationId: Joi.string().uuid().allow(null),
1189
+ }).unknown(true);
1190
+
1191
+ this.propertyTypes = {
1192
+ concUsed: "number[]",
1193
+ distances: "number[]",
1194
+ };
1195
+ }
1196
+
1197
+ validate(data: DistancesToConcLevelsCalculationResponseSchemaData): DistancesToConcLevelsCalculationResponse {
1198
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
1199
+ if (error) {
1200
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
1201
+ }
1202
+ return this.makeCalculationResponse(value);
1203
+ }
1204
+
1205
+ makeCalculationResponse(data: DistancesToConcLevelsCalculationResponseSchemaData): DistancesToConcLevelsCalculationResponse {
1206
+ return new DistancesToConcLevelsCalculationResponse(
1207
+ data.concUsed,
1208
+ data.distances,
1209
+ data.resultCode,
1210
+ data.messages,
1211
+ data.calculationElapsedTime,
1212
+ data.operationId
1213
+ );
1214
+ }
1215
+ }
1216
+
1217
+ export interface MaxConcDistanceCalculationRequestSchemaData {
1218
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1219
+ weather: Entities.Weather;
1220
+ dispersionRecords: Entities.DispersionRecord[];
1221
+ dispersionRecordCount: number;
1222
+ substrate: Entities.Substrate;
1223
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1224
+ material: Entities.Material;
1225
+ dispersionParameters: Entities.DispersionParameters;
1226
+ }
1227
+
1228
+ class MaxConcDistanceCalculationRequest extends CalculationRequestBase {
1229
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1230
+ weather: Entities.Weather;
1231
+ dispersionRecords: Entities.DispersionRecord[];
1232
+ dispersionRecordCount: number;
1233
+ substrate: Entities.Substrate;
1234
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1235
+ material: Entities.Material;
1236
+ dispersionParameters: Entities.DispersionParameters;
1237
+
1238
+ /**
1239
+ * MaxConcDistance calculation request class.
1240
+ *
1241
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
1242
+ * @param {Entities.Weather} weather - A Weather entity.
1243
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of dispersion records.
1244
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
1245
+ * @param {Entities.Substrate} substrate - A substrate entity.
1246
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
1247
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
1248
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
1249
+ */
1250
+ constructor(
1251
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
1252
+ weather: Entities.Weather,
1253
+ dispersionRecords: Entities.DispersionRecord[],
1254
+ dispersionRecordCount: number,
1255
+ substrate: Entities.Substrate,
1256
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
1257
+ material: Entities.Material,
1258
+ dispersionParameters: Entities.DispersionParameters
1259
+ ) {
1260
+ super();
1261
+ this.scalarUdmOutputs = scalarUdmOutputs;
1262
+ this.weather = weather;
1263
+ this.dispersionRecords = dispersionRecords;
1264
+ this.dispersionRecordCount = dispersionRecordCount;
1265
+ this.substrate = substrate;
1266
+ this.dispersionOutputConfig = dispersionOutputConfig;
1267
+ this.material = material;
1268
+ this.dispersionParameters = dispersionParameters;
1269
+ }
1270
+ }
1271
+
1272
+ export class MaxConcDistanceCalculationRequestSchema {
1273
+ schema: Joi.ObjectSchema;
1274
+ propertyTypes: Record<string, string>;
1275
+
1276
+ /**
1277
+ * Schema for the MaxConcDistance calculation request.
1278
+ */
1279
+ constructor() {
1280
+ this.schema = Joi.object({
1281
+ scalarUdmOutputs: new EntitySchemas.ScalarUdmOutputsSchema().schema,
1282
+ weather: new EntitySchemas.WeatherSchema().schema,
1283
+ dispersionRecords: Joi.array().items(new EntitySchemas.DispersionRecordSchema().schema).allow(null),
1284
+ dispersionRecordCount: Joi.number().integer(),
1285
+ substrate: new EntitySchemas.SubstrateSchema().schema,
1286
+ dispersionOutputConfig: new EntitySchemas.DispersionOutputConfigSchema().schema,
1287
+ material: new EntitySchemas.MaterialSchema().schema,
1288
+ dispersionParameters: new EntitySchemas.DispersionParametersSchema().schema,
1289
+ }).unknown(true);
1290
+
1291
+ this.propertyTypes = {
1292
+ scalarUdmOutputs: "Entities.ScalarUdmOutputs",
1293
+ weather: "Entities.Weather",
1294
+ dispersionRecords: "Entities.DispersionRecord[]",
1295
+ dispersionRecordCount: "number",
1296
+ substrate: "Entities.Substrate",
1297
+ dispersionOutputConfig: "Entities.DispersionOutputConfig",
1298
+ material: "Entities.Material",
1299
+ dispersionParameters: "Entities.DispersionParameters",
1300
+ };
1301
+ }
1302
+
1303
+ validate(data: MaxConcDistanceCalculationRequestSchemaData): MaxConcDistanceCalculationRequest {
1304
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
1305
+ if (error) {
1306
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
1307
+ }
1308
+ return this.makeCalculationRequest(value);
1309
+ }
1310
+
1311
+ makeCalculationRequest(data: MaxConcDistanceCalculationRequestSchemaData): MaxConcDistanceCalculationRequest {
1312
+ return new MaxConcDistanceCalculationRequest(
1313
+ data.scalarUdmOutputs,
1314
+ data.weather,
1315
+ data.dispersionRecords,
1316
+ data.dispersionRecordCount,
1317
+ data.substrate,
1318
+ data.dispersionOutputConfig,
1319
+ data.material,
1320
+ data.dispersionParameters
1321
+ );
1322
+ }
1323
+ }
1324
+
1325
+ export class MaxConcDistanceCalculation extends CalculationBase {
1326
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1327
+ weather: Entities.Weather;
1328
+ dispersionRecords: Entities.DispersionRecord[];
1329
+ dispersionRecordCount: number;
1330
+ substrate: Entities.Substrate;
1331
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1332
+ material: Entities.Material;
1333
+ dispersionParameters: Entities.DispersionParameters;
1334
+ concUsed?: number;
1335
+ concentrationRecords?: Entities.ConcentrationRecord[];
1336
+
1337
+ /**
1338
+ * Calculate the maximum concentration vs distance, i.e. the maximum concentration reached at points downwind out to the minimum concentration of interest. Dispersion results produced from a successful dispersion calculation are required as input. Include the effects of along-wind diffusion (AWD).
1339
+ *
1340
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
1341
+ * @param {Entities.Weather} weather - A Weather entity.
1342
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of dispersion records.
1343
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
1344
+ * @param {Entities.Substrate} substrate - A substrate entity.
1345
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
1346
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
1347
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
1348
+ */
1349
+ constructor(
1350
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
1351
+ weather: Entities.Weather,
1352
+ dispersionRecords: Entities.DispersionRecord[],
1353
+ dispersionRecordCount: number,
1354
+ substrate: Entities.Substrate,
1355
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
1356
+ material: Entities.Material,
1357
+ dispersionParameters: Entities.DispersionParameters
1358
+ ) {
1359
+ super();
1360
+ this.scalarUdmOutputs = scalarUdmOutputs;
1361
+ this.weather = weather;
1362
+ this.dispersionRecords = dispersionRecords;
1363
+ this.dispersionRecordCount = dispersionRecordCount;
1364
+ this.substrate = substrate;
1365
+ this.dispersionOutputConfig = dispersionOutputConfig;
1366
+ this.material = material;
1367
+ this.dispersionParameters = dispersionParameters;
1368
+ }
1369
+
1370
+ async run() {
1371
+ try {
1372
+ const request = new MaxConcDistanceCalculationRequest(
1373
+ this.scalarUdmOutputs,
1374
+ this.weather,
1375
+ this.dispersionRecords,
1376
+ this.dispersionRecordCount,
1377
+ this.substrate,
1378
+ this.dispersionOutputConfig,
1379
+ this.material,
1380
+ this.dispersionParameters
1381
+ );
1382
+
1383
+ const schema = new MaxConcDistanceCalculationRequestSchema();
1384
+ const validatedRequest = schema.validate(request);
1385
+
1386
+ const requestJson = JSON.stringify(validatedRequest);
1387
+ const url = `${getAnalyticsApiTarget()}calculatemaxconcdistance?clientId=${getClientAliasId()}`;
1388
+
1389
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
1390
+
1391
+ const response = await this.postRequest(url, requestJson);
1392
+
1393
+ if (response.status >= 200 && response.status < 300) {
1394
+ const schema = new MaxConcDistanceCalculationResponseSchema();
1395
+ const validatedResponse = schema.validate(response.data);
1396
+
1397
+ this.resultCode = validatedResponse.resultCode;
1398
+ if (this.resultCode === Enums.ResultCode.SUCCESS) {
1399
+ this.concUsed = validatedResponse.concUsed;
1400
+ this.concentrationRecords = validatedResponse.concentrationRecords;
1401
+ this.resultCode = validatedResponse.resultCode;
1402
+ this.messages = validatedResponse.messages ?? [];
1403
+ this.calculationElapsedTime = validatedResponse.calculationElapsedTime;
1404
+ this.operationId = validatedResponse.operationId;
1405
+ } else {
1406
+ this.messages.push(...(validatedResponse.messages ?? []));
1407
+ }
1408
+ } else {
1409
+ this.handleFailedResponse(response);
1410
+ }
1411
+ } catch (error) {
1412
+ if (error instanceof Error) {
1413
+ this.messages.push(`Error: ${error.message}`);
1414
+ } else {
1415
+ this.messages.push(`Unexpected error: ${JSON.stringify(error)}`);
1416
+ }
1417
+ console.error(error);
1418
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
1419
+ }
1420
+
1421
+ return this.resultCode;
1422
+ }
1423
+
1424
+ toString() {
1425
+ const parts = ["* MaxConcDistance"];
1426
+
1427
+ parts.push(`concUsed: ${String(this.concUsed)}`);
1428
+ parts.push("*** concentrationRecords:");
1429
+ parts.push(
1430
+ this.concentrationRecords && this.concentrationRecords.length > 0
1431
+ ? this.concentrationRecords.map((point) => `concentrationRecordsElement: ${point}`).join("\n")
1432
+ : "concentrationRecords does not contain any elements"
1433
+ );
1434
+ parts.push(`resultCode: ${String(this.resultCode)}`);
1435
+ parts.push("*** messages:");
1436
+ parts.push(`messages: ${this.messages !== undefined ? this.messages : "(None)"}`);
1437
+ parts.push(`calculationElapsedTime: ${this.calculationElapsedTime !== undefined ? this.calculationElapsedTime : "(None)"}`);
1438
+ parts.push(`operationId: ${this.operationId !== undefined ? this.operationId : "(None)"}`);
1439
+
1440
+ return parts.join("\n");
1441
+ }
1442
+ }
1443
+
1444
+ export class MaxConcDistanceCalculationResponse extends CalculationResponseBase {
1445
+ concUsed: number;
1446
+ concentrationRecords: Entities.ConcentrationRecord[];
1447
+
1448
+ /**
1449
+ * MaxConcDistance calculation response class.
1450
+ *
1451
+ * @param {number} concUsed - Concentration of interest.
1452
+ * @param {Entities.ConcentrationRecord[]} concentrationRecords - An array of maximum concentration at x, y, z coordinates.
1453
+ */
1454
+ constructor(
1455
+ concUsed: number,
1456
+ concentrationRecords: Entities.ConcentrationRecord[],
1457
+ resultCode: Enums.ResultCode,
1458
+ messages: string[],
1459
+ calculationElapsedTime: number,
1460
+ operationId: string
1461
+ ) {
1462
+ super();
1463
+ this.concUsed = concUsed;
1464
+ this.concentrationRecords = concentrationRecords;
1465
+ this.resultCode = resultCode;
1466
+ this.messages = messages;
1467
+ this.calculationElapsedTime = calculationElapsedTime;
1468
+ this.operationId = operationId;
1469
+ }
1470
+
1471
+ initialiseFromDictionary(data: { [key: string]: unknown }) {
1472
+ if (data.concUsed !== undefined && typeof data.concUsed === "number") {
1473
+ this.concUsed = data.concUsed as number;
1474
+ }
1475
+ if (data.concentrationRecords && Array.isArray(data.concentrationRecords)) {
1476
+ this.concentrationRecords = data.concentrationRecords.map(
1477
+ (item) => {
1478
+ const record = new Entities.ConcentrationRecord();
1479
+ record.initialiseFromDictionary(item);
1480
+ return record;
1481
+ }
1482
+ );
1483
+ }
1484
+ if (data.resultCode !== undefined && (typeof data.resultCode === "string" || typeof data.resultCode === "number")) {
1485
+ this.resultCode = data.resultCode as Enums.ResultCode;
1486
+ }
1487
+ this.messages = this.messages ?? [];
1488
+ if (data.messages && Array.isArray(data.messages)) {
1489
+ this.messages.push(...data.messages);
1490
+ }
1491
+ if (data.calculationElapsedTime !== undefined && typeof data.calculationElapsedTime === "number") {
1492
+ this.calculationElapsedTime = data.calculationElapsedTime as number;
1493
+ }
1494
+ if (data.operationId !== undefined && typeof data.operationId === "string") {
1495
+ this.operationId = data.operationId as string;
1496
+ }
1497
+ }
1498
+ }
1499
+
1500
+ export interface MaxConcDistanceCalculationResponseSchemaData {
1501
+ concUsed: number;
1502
+ concentrationRecords: Entities.ConcentrationRecord[];
1503
+ resultCode: Enums.ResultCode;
1504
+ messages: string[];
1505
+ calculationElapsedTime: number;
1506
+ operationId: string;
1507
+ }
1508
+
1509
+ export class MaxConcDistanceCalculationResponseSchema {
1510
+ schema: Joi.ObjectSchema;
1511
+ propertyTypes: Record<string, string>;
1512
+
1513
+ /**
1514
+ * Schema for the MaxConcDistance calculation response.
1515
+ */
1516
+ constructor() {
1517
+ this.schema = Joi.object({
1518
+ concUsed: Joi.number().unsafe(),
1519
+ concentrationRecords: Joi.array().items(new EntitySchemas.ConcentrationRecordSchema().schema).allow(null),
1520
+ resultCode: Joi.string().valid(...Object.values(Enums.ResultCode)),
1521
+ messages: Joi.array().items(Joi.string()),
1522
+ calculationElapsedTime: Joi.number().unsafe(),
1523
+ operationId: Joi.string().uuid().allow(null),
1524
+ }).unknown(true);
1525
+
1526
+ this.propertyTypes = {
1527
+ concUsed: "number",
1528
+ concentrationRecords: "Entities.ConcentrationRecord[]",
1529
+ };
1530
+ }
1531
+
1532
+ validate(data: MaxConcDistanceCalculationResponseSchemaData): MaxConcDistanceCalculationResponse {
1533
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
1534
+ if (error) {
1535
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
1536
+ }
1537
+ return this.makeCalculationResponse(value);
1538
+ }
1539
+
1540
+ makeCalculationResponse(data: MaxConcDistanceCalculationResponseSchemaData): MaxConcDistanceCalculationResponse {
1541
+ return new MaxConcDistanceCalculationResponse(
1542
+ data.concUsed,
1543
+ data.concentrationRecords,
1544
+ data.resultCode,
1545
+ data.messages,
1546
+ data.calculationElapsedTime,
1547
+ data.operationId
1548
+ );
1549
+ }
1550
+ }
1551
+
1552
+ export interface MaxConcFootprintCalculationRequestSchemaData {
1553
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1554
+ weather: Entities.Weather;
1555
+ dispersionRecords: Entities.DispersionRecord[];
1556
+ dispersionRecordCount: number;
1557
+ substrate: Entities.Substrate;
1558
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1559
+ material: Entities.Material;
1560
+ dispersionParameters: Entities.DispersionParameters;
1561
+ }
1562
+
1563
+ class MaxConcFootprintCalculationRequest extends CalculationRequestBase {
1564
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1565
+ weather: Entities.Weather;
1566
+ dispersionRecords: Entities.DispersionRecord[];
1567
+ dispersionRecordCount: number;
1568
+ substrate: Entities.Substrate;
1569
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1570
+ material: Entities.Material;
1571
+ dispersionParameters: Entities.DispersionParameters;
1572
+
1573
+ /**
1574
+ * MaxConcFootprint calculation request class.
1575
+ *
1576
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
1577
+ * @param {Entities.Weather} weather - A Weather entity.
1578
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
1579
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
1580
+ * @param {Entities.Substrate} substrate - A Substrate entity.
1581
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
1582
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
1583
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
1584
+ */
1585
+ constructor(
1586
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
1587
+ weather: Entities.Weather,
1588
+ dispersionRecords: Entities.DispersionRecord[],
1589
+ dispersionRecordCount: number,
1590
+ substrate: Entities.Substrate,
1591
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
1592
+ material: Entities.Material,
1593
+ dispersionParameters: Entities.DispersionParameters
1594
+ ) {
1595
+ super();
1596
+ this.scalarUdmOutputs = scalarUdmOutputs;
1597
+ this.weather = weather;
1598
+ this.dispersionRecords = dispersionRecords;
1599
+ this.dispersionRecordCount = dispersionRecordCount;
1600
+ this.substrate = substrate;
1601
+ this.dispersionOutputConfig = dispersionOutputConfig;
1602
+ this.material = material;
1603
+ this.dispersionParameters = dispersionParameters;
1604
+ }
1605
+ }
1606
+
1607
+ export class MaxConcFootprintCalculationRequestSchema {
1608
+ schema: Joi.ObjectSchema;
1609
+ propertyTypes: Record<string, string>;
1610
+
1611
+ /**
1612
+ * Schema for the MaxConcFootprint calculation request.
1613
+ */
1614
+ constructor() {
1615
+ this.schema = Joi.object({
1616
+ scalarUdmOutputs: new EntitySchemas.ScalarUdmOutputsSchema().schema,
1617
+ weather: new EntitySchemas.WeatherSchema().schema,
1618
+ dispersionRecords: Joi.array().items(new EntitySchemas.DispersionRecordSchema().schema).allow(null),
1619
+ dispersionRecordCount: Joi.number().integer(),
1620
+ substrate: new EntitySchemas.SubstrateSchema().schema,
1621
+ dispersionOutputConfig: new EntitySchemas.DispersionOutputConfigSchema().schema,
1622
+ material: new EntitySchemas.MaterialSchema().schema,
1623
+ dispersionParameters: new EntitySchemas.DispersionParametersSchema().schema,
1624
+ }).unknown(true);
1625
+
1626
+ this.propertyTypes = {
1627
+ scalarUdmOutputs: "Entities.ScalarUdmOutputs",
1628
+ weather: "Entities.Weather",
1629
+ dispersionRecords: "Entities.DispersionRecord[]",
1630
+ dispersionRecordCount: "number",
1631
+ substrate: "Entities.Substrate",
1632
+ dispersionOutputConfig: "Entities.DispersionOutputConfig",
1633
+ material: "Entities.Material",
1634
+ dispersionParameters: "Entities.DispersionParameters",
1635
+ };
1636
+ }
1637
+
1638
+ validate(data: MaxConcFootprintCalculationRequestSchemaData): MaxConcFootprintCalculationRequest {
1639
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
1640
+ if (error) {
1641
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
1642
+ }
1643
+ return this.makeCalculationRequest(value);
1644
+ }
1645
+
1646
+ makeCalculationRequest(data: MaxConcFootprintCalculationRequestSchemaData): MaxConcFootprintCalculationRequest {
1647
+ return new MaxConcFootprintCalculationRequest(
1648
+ data.scalarUdmOutputs,
1649
+ data.weather,
1650
+ data.dispersionRecords,
1651
+ data.dispersionRecordCount,
1652
+ data.substrate,
1653
+ data.dispersionOutputConfig,
1654
+ data.material,
1655
+ data.dispersionParameters
1656
+ );
1657
+ }
1658
+ }
1659
+
1660
+ export class MaxConcFootprintCalculation extends CalculationBase {
1661
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1662
+ weather: Entities.Weather;
1663
+ dispersionRecords: Entities.DispersionRecord[];
1664
+ dispersionRecordCount: number;
1665
+ substrate: Entities.Substrate;
1666
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1667
+ material: Entities.Material;
1668
+ dispersionParameters: Entities.DispersionParameters;
1669
+ concUsed?: number;
1670
+ contourPoints?: Entities.LocalPosition[];
1671
+
1672
+ /**
1673
+ * Calculate the maximum footprint of the cloud for a given concentration level. The output is a contour line defined by a set of x,y values.
1674
+ *
1675
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
1676
+ * @param {Entities.Weather} weather - A Weather entity.
1677
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
1678
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
1679
+ * @param {Entities.Substrate} substrate - A Substrate entity.
1680
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
1681
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
1682
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
1683
+ */
1684
+ constructor(
1685
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
1686
+ weather: Entities.Weather,
1687
+ dispersionRecords: Entities.DispersionRecord[],
1688
+ dispersionRecordCount: number,
1689
+ substrate: Entities.Substrate,
1690
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
1691
+ material: Entities.Material,
1692
+ dispersionParameters: Entities.DispersionParameters
1693
+ ) {
1694
+ super();
1695
+ this.scalarUdmOutputs = scalarUdmOutputs;
1696
+ this.weather = weather;
1697
+ this.dispersionRecords = dispersionRecords;
1698
+ this.dispersionRecordCount = dispersionRecordCount;
1699
+ this.substrate = substrate;
1700
+ this.dispersionOutputConfig = dispersionOutputConfig;
1701
+ this.material = material;
1702
+ this.dispersionParameters = dispersionParameters;
1703
+ }
1704
+
1705
+ async run() {
1706
+ try {
1707
+ const request = new MaxConcFootprintCalculationRequest(
1708
+ this.scalarUdmOutputs,
1709
+ this.weather,
1710
+ this.dispersionRecords,
1711
+ this.dispersionRecordCount,
1712
+ this.substrate,
1713
+ this.dispersionOutputConfig,
1714
+ this.material,
1715
+ this.dispersionParameters
1716
+ );
1717
+
1718
+ const schema = new MaxConcFootprintCalculationRequestSchema();
1719
+ const validatedRequest = schema.validate(request);
1720
+
1721
+ const requestJson = JSON.stringify(validatedRequest);
1722
+ const url = `${getAnalyticsApiTarget()}calculatemaxconcfootprint?clientId=${getClientAliasId()}`;
1723
+
1724
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
1725
+
1726
+ const response = await this.postRequest(url, requestJson);
1727
+
1728
+ if (response.status >= 200 && response.status < 300) {
1729
+ const schema = new MaxConcFootprintCalculationResponseSchema();
1730
+ const validatedResponse = schema.validate(response.data);
1731
+
1732
+ this.resultCode = validatedResponse.resultCode;
1733
+ if (this.resultCode === Enums.ResultCode.SUCCESS) {
1734
+ this.concUsed = validatedResponse.concUsed;
1735
+ this.contourPoints = validatedResponse.contourPoints;
1736
+ this.resultCode = validatedResponse.resultCode;
1737
+ this.messages = validatedResponse.messages ?? [];
1738
+ this.calculationElapsedTime = validatedResponse.calculationElapsedTime;
1739
+ this.operationId = validatedResponse.operationId;
1740
+ } else {
1741
+ this.messages.push(...(validatedResponse.messages ?? []));
1742
+ }
1743
+ } else {
1744
+ this.handleFailedResponse(response);
1745
+ }
1746
+ } catch (error) {
1747
+ if (error instanceof Error) {
1748
+ this.messages.push(`Error: ${error.message}`);
1749
+ } else {
1750
+ this.messages.push(`Unexpected error: ${JSON.stringify(error)}`);
1751
+ }
1752
+ console.error(error);
1753
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
1754
+ }
1755
+
1756
+ return this.resultCode;
1757
+ }
1758
+
1759
+ toString() {
1760
+ const parts = ["* MaxConcFootprint"];
1761
+
1762
+ parts.push(`concUsed: ${String(this.concUsed)}`);
1763
+ parts.push("*** contourPoints:");
1764
+ parts.push(
1765
+ this.contourPoints && this.contourPoints.length > 0
1766
+ ? this.contourPoints.map((point) => `contourPointsElement: ${point}`).join("\n")
1767
+ : "contourPoints does not contain any elements"
1768
+ );
1769
+ parts.push(`resultCode: ${String(this.resultCode)}`);
1770
+ parts.push("*** messages:");
1771
+ parts.push(`messages: ${this.messages !== undefined ? this.messages : "(None)"}`);
1772
+ parts.push(`calculationElapsedTime: ${this.calculationElapsedTime !== undefined ? this.calculationElapsedTime : "(None)"}`);
1773
+ parts.push(`operationId: ${this.operationId !== undefined ? this.operationId : "(None)"}`);
1774
+
1775
+ return parts.join("\n");
1776
+ }
1777
+ }
1778
+
1779
+ export class MaxConcFootprintCalculationResponse extends CalculationResponseBase {
1780
+ concUsed: number;
1781
+ contourPoints: Entities.LocalPosition[];
1782
+
1783
+ /**
1784
+ * MaxConcFootprint calculation response class.
1785
+ *
1786
+ * @param {number} concUsed - Concentration of interest.
1787
+ * @param {Entities.LocalPosition[]} contourPoints - An Array of points along the footprint contour.
1788
+ */
1789
+ constructor(
1790
+ concUsed: number,
1791
+ contourPoints: Entities.LocalPosition[],
1792
+ resultCode: Enums.ResultCode,
1793
+ messages: string[],
1794
+ calculationElapsedTime: number,
1795
+ operationId: string
1796
+ ) {
1797
+ super();
1798
+ this.concUsed = concUsed;
1799
+ this.contourPoints = contourPoints;
1800
+ this.resultCode = resultCode;
1801
+ this.messages = messages;
1802
+ this.calculationElapsedTime = calculationElapsedTime;
1803
+ this.operationId = operationId;
1804
+ }
1805
+
1806
+ initialiseFromDictionary(data: { [key: string]: unknown }) {
1807
+ if (data.concUsed !== undefined && typeof data.concUsed === "number") {
1808
+ this.concUsed = data.concUsed as number;
1809
+ }
1810
+ if (data.contourPoints && Array.isArray(data.contourPoints)) {
1811
+ this.contourPoints = data.contourPoints.map(
1812
+ (item) => {
1813
+ const record = new Entities.LocalPosition();
1814
+ record.initialiseFromDictionary(item);
1815
+ return record;
1816
+ }
1817
+ );
1818
+ }
1819
+ if (data.resultCode !== undefined && (typeof data.resultCode === "string" || typeof data.resultCode === "number")) {
1820
+ this.resultCode = data.resultCode as Enums.ResultCode;
1821
+ }
1822
+ this.messages = this.messages ?? [];
1823
+ if (data.messages && Array.isArray(data.messages)) {
1824
+ this.messages.push(...data.messages);
1825
+ }
1826
+ if (data.calculationElapsedTime !== undefined && typeof data.calculationElapsedTime === "number") {
1827
+ this.calculationElapsedTime = data.calculationElapsedTime as number;
1828
+ }
1829
+ if (data.operationId !== undefined && typeof data.operationId === "string") {
1830
+ this.operationId = data.operationId as string;
1831
+ }
1832
+ }
1833
+ }
1834
+
1835
+ export interface MaxConcFootprintCalculationResponseSchemaData {
1836
+ concUsed: number;
1837
+ contourPoints: Entities.LocalPosition[];
1838
+ resultCode: Enums.ResultCode;
1839
+ messages: string[];
1840
+ calculationElapsedTime: number;
1841
+ operationId: string;
1842
+ }
1843
+
1844
+ export class MaxConcFootprintCalculationResponseSchema {
1845
+ schema: Joi.ObjectSchema;
1846
+ propertyTypes: Record<string, string>;
1847
+
1848
+ /**
1849
+ * Schema for the MaxConcFootprint calculation response.
1850
+ */
1851
+ constructor() {
1852
+ this.schema = Joi.object({
1853
+ concUsed: Joi.number().unsafe(),
1854
+ contourPoints: Joi.array().items(new EntitySchemas.LocalPositionSchema().schema).allow(null),
1855
+ resultCode: Joi.string().valid(...Object.values(Enums.ResultCode)),
1856
+ messages: Joi.array().items(Joi.string()),
1857
+ calculationElapsedTime: Joi.number().unsafe(),
1858
+ operationId: Joi.string().uuid().allow(null),
1859
+ }).unknown(true);
1860
+
1861
+ this.propertyTypes = {
1862
+ concUsed: "number",
1863
+ contourPoints: "Entities.LocalPosition[]",
1864
+ };
1865
+ }
1866
+
1867
+ validate(data: MaxConcFootprintCalculationResponseSchemaData): MaxConcFootprintCalculationResponse {
1868
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
1869
+ if (error) {
1870
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
1871
+ }
1872
+ return this.makeCalculationResponse(value);
1873
+ }
1874
+
1875
+ makeCalculationResponse(data: MaxConcFootprintCalculationResponseSchemaData): MaxConcFootprintCalculationResponse {
1876
+ return new MaxConcFootprintCalculationResponse(
1877
+ data.concUsed,
1878
+ data.contourPoints,
1879
+ data.resultCode,
1880
+ data.messages,
1881
+ data.calculationElapsedTime,
1882
+ data.operationId
1883
+ );
1884
+ }
1885
+ }
1886
+
1887
+ export interface MaxDistanceToConcCalculationRequestSchemaData {
1888
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1889
+ weather: Entities.Weather;
1890
+ dispersionRecords: Entities.DispersionRecord[];
1891
+ dispersionRecordCount: number;
1892
+ substrate: Entities.Substrate;
1893
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1894
+ dispersionParameters: Entities.DispersionParameters;
1895
+ material: Entities.Material;
1896
+ }
1897
+
1898
+ class MaxDistanceToConcCalculationRequest extends CalculationRequestBase {
1899
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1900
+ weather: Entities.Weather;
1901
+ dispersionRecords: Entities.DispersionRecord[];
1902
+ dispersionRecordCount: number;
1903
+ substrate: Entities.Substrate;
1904
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
1905
+ dispersionParameters: Entities.DispersionParameters;
1906
+ material: Entities.Material;
1907
+
1908
+ /**
1909
+ * MaxDistanceToConc calculation request class.
1910
+ *
1911
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
1912
+ * @param {Entities.Weather} weather - A Weather entity.
1913
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
1914
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
1915
+ * @param {Entities.Substrate} substrate - A Substrate entity.
1916
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
1917
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
1918
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
1919
+ */
1920
+ constructor(
1921
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
1922
+ weather: Entities.Weather,
1923
+ dispersionRecords: Entities.DispersionRecord[],
1924
+ dispersionRecordCount: number,
1925
+ substrate: Entities.Substrate,
1926
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
1927
+ dispersionParameters: Entities.DispersionParameters,
1928
+ material: Entities.Material
1929
+ ) {
1930
+ super();
1931
+ this.scalarUdmOutputs = scalarUdmOutputs;
1932
+ this.weather = weather;
1933
+ this.dispersionRecords = dispersionRecords;
1934
+ this.dispersionRecordCount = dispersionRecordCount;
1935
+ this.substrate = substrate;
1936
+ this.dispersionOutputConfig = dispersionOutputConfig;
1937
+ this.dispersionParameters = dispersionParameters;
1938
+ this.material = material;
1939
+ }
1940
+ }
1941
+
1942
+ export class MaxDistanceToConcCalculationRequestSchema {
1943
+ schema: Joi.ObjectSchema;
1944
+ propertyTypes: Record<string, string>;
1945
+
1946
+ /**
1947
+ * Schema for the MaxDistanceToConc calculation request.
1948
+ */
1949
+ constructor() {
1950
+ this.schema = Joi.object({
1951
+ scalarUdmOutputs: new EntitySchemas.ScalarUdmOutputsSchema().schema,
1952
+ weather: new EntitySchemas.WeatherSchema().schema,
1953
+ dispersionRecords: Joi.array().items(new EntitySchemas.DispersionRecordSchema().schema).allow(null),
1954
+ dispersionRecordCount: Joi.number().integer(),
1955
+ substrate: new EntitySchemas.SubstrateSchema().schema,
1956
+ dispersionOutputConfig: new EntitySchemas.DispersionOutputConfigSchema().schema,
1957
+ dispersionParameters: new EntitySchemas.DispersionParametersSchema().schema,
1958
+ material: new EntitySchemas.MaterialSchema().schema,
1959
+ }).unknown(true);
1960
+
1961
+ this.propertyTypes = {
1962
+ scalarUdmOutputs: "Entities.ScalarUdmOutputs",
1963
+ weather: "Entities.Weather",
1964
+ dispersionRecords: "Entities.DispersionRecord[]",
1965
+ dispersionRecordCount: "number",
1966
+ substrate: "Entities.Substrate",
1967
+ dispersionOutputConfig: "Entities.DispersionOutputConfig",
1968
+ dispersionParameters: "Entities.DispersionParameters",
1969
+ material: "Entities.Material",
1970
+ };
1971
+ }
1972
+
1973
+ validate(data: MaxDistanceToConcCalculationRequestSchemaData): MaxDistanceToConcCalculationRequest {
1974
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
1975
+ if (error) {
1976
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
1977
+ }
1978
+ return this.makeCalculationRequest(value);
1979
+ }
1980
+
1981
+ makeCalculationRequest(data: MaxDistanceToConcCalculationRequestSchemaData): MaxDistanceToConcCalculationRequest {
1982
+ return new MaxDistanceToConcCalculationRequest(
1983
+ data.scalarUdmOutputs,
1984
+ data.weather,
1985
+ data.dispersionRecords,
1986
+ data.dispersionRecordCount,
1987
+ data.substrate,
1988
+ data.dispersionOutputConfig,
1989
+ data.dispersionParameters,
1990
+ data.material
1991
+ );
1992
+ }
1993
+ }
1994
+
1995
+ export class MaxDistanceToConcCalculation extends CalculationBase {
1996
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
1997
+ weather: Entities.Weather;
1998
+ dispersionRecords: Entities.DispersionRecord[];
1999
+ dispersionRecordCount: number;
2000
+ substrate: Entities.Substrate;
2001
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
2002
+ dispersionParameters: Entities.DispersionParameters;
2003
+ material: Entities.Material;
2004
+ concUsed?: number;
2005
+ distance?: number;
2006
+
2007
+ /**
2008
+ * Calculates the maximum downwind distance to a concentration level in the direction of the wind, at the current effect height and averaging time.
2009
+ *
2010
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion results.
2011
+ * @param {Entities.Weather} weather - A Weather entity.
2012
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
2013
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
2014
+ * @param {Entities.Substrate} substrate - A Substrate entity.
2015
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
2016
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
2017
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
2018
+ */
2019
+ constructor(
2020
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
2021
+ weather: Entities.Weather,
2022
+ dispersionRecords: Entities.DispersionRecord[],
2023
+ dispersionRecordCount: number,
2024
+ substrate: Entities.Substrate,
2025
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
2026
+ dispersionParameters: Entities.DispersionParameters,
2027
+ material: Entities.Material
2028
+ ) {
2029
+ super();
2030
+ this.scalarUdmOutputs = scalarUdmOutputs;
2031
+ this.weather = weather;
2032
+ this.dispersionRecords = dispersionRecords;
2033
+ this.dispersionRecordCount = dispersionRecordCount;
2034
+ this.substrate = substrate;
2035
+ this.dispersionOutputConfig = dispersionOutputConfig;
2036
+ this.dispersionParameters = dispersionParameters;
2037
+ this.material = material;
2038
+ }
2039
+
2040
+ async run() {
2041
+ try {
2042
+ const request = new MaxDistanceToConcCalculationRequest(
2043
+ this.scalarUdmOutputs,
2044
+ this.weather,
2045
+ this.dispersionRecords,
2046
+ this.dispersionRecordCount,
2047
+ this.substrate,
2048
+ this.dispersionOutputConfig,
2049
+ this.dispersionParameters,
2050
+ this.material
2051
+ );
2052
+
2053
+ const schema = new MaxDistanceToConcCalculationRequestSchema();
2054
+ const validatedRequest = schema.validate(request);
2055
+
2056
+ const requestJson = JSON.stringify(validatedRequest);
2057
+ const url = `${getAnalyticsApiTarget()}calculatemaxdistancetoconc?clientId=${getClientAliasId()}`;
2058
+
2059
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
2060
+
2061
+ const response = await this.postRequest(url, requestJson);
2062
+
2063
+ if (response.status >= 200 && response.status < 300) {
2064
+ const schema = new MaxDistanceToConcCalculationResponseSchema();
2065
+ const validatedResponse = schema.validate(response.data);
2066
+
2067
+ this.resultCode = validatedResponse.resultCode;
2068
+ if (this.resultCode === Enums.ResultCode.SUCCESS) {
2069
+ this.concUsed = validatedResponse.concUsed;
2070
+ this.distance = validatedResponse.distance;
2071
+ this.resultCode = validatedResponse.resultCode;
2072
+ this.messages = validatedResponse.messages ?? [];
2073
+ this.calculationElapsedTime = validatedResponse.calculationElapsedTime;
2074
+ this.operationId = validatedResponse.operationId;
2075
+ } else {
2076
+ this.messages.push(...(validatedResponse.messages ?? []));
2077
+ }
2078
+ } else {
2079
+ this.handleFailedResponse(response);
2080
+ }
2081
+ } catch (error) {
2082
+ if (error instanceof Error) {
2083
+ this.messages.push(`Error: ${error.message}`);
2084
+ } else {
2085
+ this.messages.push(`Unexpected error: ${JSON.stringify(error)}`);
2086
+ }
2087
+ console.error(error);
2088
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
2089
+ }
2090
+
2091
+ return this.resultCode;
2092
+ }
2093
+
2094
+ toString() {
2095
+ const parts = ["* MaxDistanceToConc"];
2096
+
2097
+ parts.push(`concUsed: ${String(this.concUsed)}`);
2098
+ parts.push(`distance: ${String(this.distance)}`);
2099
+ parts.push(`resultCode: ${String(this.resultCode)}`);
2100
+ parts.push("*** messages:");
2101
+ parts.push(`messages: ${this.messages !== undefined ? this.messages : "(None)"}`);
2102
+ parts.push(`calculationElapsedTime: ${this.calculationElapsedTime !== undefined ? this.calculationElapsedTime : "(None)"}`);
2103
+ parts.push(`operationId: ${this.operationId !== undefined ? this.operationId : "(None)"}`);
2104
+
2105
+ return parts.join("\n");
2106
+ }
2107
+ }
2108
+
2109
+ export class MaxDistanceToConcCalculationResponse extends CalculationResponseBase {
2110
+ concUsed: number;
2111
+ distance: number;
2112
+
2113
+ /**
2114
+ * MaxDistanceToConc calculation response class.
2115
+ *
2116
+ * @param {number} concUsed - Concentration of interest.
2117
+ * @param {number} distance - Maximum distance to concentration of interest.
2118
+ */
2119
+ constructor(
2120
+ concUsed: number,
2121
+ distance: number,
2122
+ resultCode: Enums.ResultCode,
2123
+ messages: string[],
2124
+ calculationElapsedTime: number,
2125
+ operationId: string
2126
+ ) {
2127
+ super();
2128
+ this.concUsed = concUsed;
2129
+ this.distance = distance;
2130
+ this.resultCode = resultCode;
2131
+ this.messages = messages;
2132
+ this.calculationElapsedTime = calculationElapsedTime;
2133
+ this.operationId = operationId;
2134
+ }
2135
+
2136
+ initialiseFromDictionary(data: { [key: string]: unknown }) {
2137
+ if (data.concUsed !== undefined && typeof data.concUsed === "number") {
2138
+ this.concUsed = data.concUsed as number;
2139
+ }
2140
+ if (data.distance !== undefined && typeof data.distance === "number") {
2141
+ this.distance = data.distance as number;
2142
+ }
2143
+ if (data.resultCode !== undefined && (typeof data.resultCode === "string" || typeof data.resultCode === "number")) {
2144
+ this.resultCode = data.resultCode as Enums.ResultCode;
2145
+ }
2146
+ this.messages = this.messages ?? [];
2147
+ if (data.messages && Array.isArray(data.messages)) {
2148
+ this.messages.push(...data.messages);
2149
+ }
2150
+ if (data.calculationElapsedTime !== undefined && typeof data.calculationElapsedTime === "number") {
2151
+ this.calculationElapsedTime = data.calculationElapsedTime as number;
2152
+ }
2153
+ if (data.operationId !== undefined && typeof data.operationId === "string") {
2154
+ this.operationId = data.operationId as string;
2155
+ }
2156
+ }
2157
+ }
2158
+
2159
+ export interface MaxDistanceToConcCalculationResponseSchemaData {
2160
+ concUsed: number;
2161
+ distance: number;
2162
+ resultCode: Enums.ResultCode;
2163
+ messages: string[];
2164
+ calculationElapsedTime: number;
2165
+ operationId: string;
2166
+ }
2167
+
2168
+ export class MaxDistanceToConcCalculationResponseSchema {
2169
+ schema: Joi.ObjectSchema;
2170
+ propertyTypes: Record<string, string>;
2171
+
2172
+ /**
2173
+ * Schema for the MaxDistanceToConc calculation response.
2174
+ */
2175
+ constructor() {
2176
+ this.schema = Joi.object({
2177
+ concUsed: Joi.number().unsafe(),
2178
+ distance: Joi.number().unsafe(),
2179
+ resultCode: Joi.string().valid(...Object.values(Enums.ResultCode)),
2180
+ messages: Joi.array().items(Joi.string()),
2181
+ calculationElapsedTime: Joi.number().unsafe(),
2182
+ operationId: Joi.string().uuid().allow(null),
2183
+ }).unknown(true);
2184
+
2185
+ this.propertyTypes = {
2186
+ concUsed: "number",
2187
+ distance: "number",
2188
+ };
2189
+ }
2190
+
2191
+ validate(data: MaxDistanceToConcCalculationResponseSchemaData): MaxDistanceToConcCalculationResponse {
2192
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
2193
+ if (error) {
2194
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
2195
+ }
2196
+ return this.makeCalculationResponse(value);
2197
+ }
2198
+
2199
+ makeCalculationResponse(data: MaxDistanceToConcCalculationResponseSchemaData): MaxDistanceToConcCalculationResponse {
2200
+ return new MaxDistanceToConcCalculationResponse(
2201
+ data.concUsed,
2202
+ data.distance,
2203
+ data.resultCode,
2204
+ data.messages,
2205
+ data.calculationElapsedTime,
2206
+ data.operationId
2207
+ );
2208
+ }
2209
+ }
2210
+
2211
+ export interface SideviewAtTimeCalculationRequestSchemaData {
2212
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
2213
+ weather: Entities.Weather;
2214
+ dispersionRecords: Entities.DispersionRecord[];
2215
+ dispersionRecordCount: number;
2216
+ substrate: Entities.Substrate;
2217
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
2218
+ material: Entities.Material;
2219
+ dispersionParameters: Entities.DispersionParameters;
2220
+ }
2221
+
2222
+ class SideviewAtTimeCalculationRequest extends CalculationRequestBase {
2223
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
2224
+ weather: Entities.Weather;
2225
+ dispersionRecords: Entities.DispersionRecord[];
2226
+ dispersionRecordCount: number;
2227
+ substrate: Entities.Substrate;
2228
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
2229
+ material: Entities.Material;
2230
+ dispersionParameters: Entities.DispersionParameters;
2231
+
2232
+ /**
2233
+ * SideviewAtTime calculation request class.
2234
+ *
2235
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion outputs.
2236
+ * @param {Entities.Weather} weather - A Weather entity.
2237
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
2238
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
2239
+ * @param {Entities.Substrate} substrate - A substrate entity.
2240
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
2241
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
2242
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
2243
+ */
2244
+ constructor(
2245
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
2246
+ weather: Entities.Weather,
2247
+ dispersionRecords: Entities.DispersionRecord[],
2248
+ dispersionRecordCount: number,
2249
+ substrate: Entities.Substrate,
2250
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
2251
+ material: Entities.Material,
2252
+ dispersionParameters: Entities.DispersionParameters
2253
+ ) {
2254
+ super();
2255
+ this.scalarUdmOutputs = scalarUdmOutputs;
2256
+ this.weather = weather;
2257
+ this.dispersionRecords = dispersionRecords;
2258
+ this.dispersionRecordCount = dispersionRecordCount;
2259
+ this.substrate = substrate;
2260
+ this.dispersionOutputConfig = dispersionOutputConfig;
2261
+ this.material = material;
2262
+ this.dispersionParameters = dispersionParameters;
2263
+ }
2264
+ }
2265
+
2266
+ export class SideviewAtTimeCalculationRequestSchema {
2267
+ schema: Joi.ObjectSchema;
2268
+ propertyTypes: Record<string, string>;
2269
+
2270
+ /**
2271
+ * Schema for the SideviewAtTime calculation request.
2272
+ */
2273
+ constructor() {
2274
+ this.schema = Joi.object({
2275
+ scalarUdmOutputs: new EntitySchemas.ScalarUdmOutputsSchema().schema,
2276
+ weather: new EntitySchemas.WeatherSchema().schema,
2277
+ dispersionRecords: Joi.array().items(new EntitySchemas.DispersionRecordSchema().schema).allow(null),
2278
+ dispersionRecordCount: Joi.number().integer(),
2279
+ substrate: new EntitySchemas.SubstrateSchema().schema,
2280
+ dispersionOutputConfig: new EntitySchemas.DispersionOutputConfigSchema().schema,
2281
+ material: new EntitySchemas.MaterialSchema().schema,
2282
+ dispersionParameters: new EntitySchemas.DispersionParametersSchema().schema,
2283
+ }).unknown(true);
2284
+
2285
+ this.propertyTypes = {
2286
+ scalarUdmOutputs: "Entities.ScalarUdmOutputs",
2287
+ weather: "Entities.Weather",
2288
+ dispersionRecords: "Entities.DispersionRecord[]",
2289
+ dispersionRecordCount: "number",
2290
+ substrate: "Entities.Substrate",
2291
+ dispersionOutputConfig: "Entities.DispersionOutputConfig",
2292
+ material: "Entities.Material",
2293
+ dispersionParameters: "Entities.DispersionParameters",
2294
+ };
2295
+ }
2296
+
2297
+ validate(data: SideviewAtTimeCalculationRequestSchemaData): SideviewAtTimeCalculationRequest {
2298
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
2299
+ if (error) {
2300
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
2301
+ }
2302
+ return this.makeCalculationRequest(value);
2303
+ }
2304
+
2305
+ makeCalculationRequest(data: SideviewAtTimeCalculationRequestSchemaData): SideviewAtTimeCalculationRequest {
2306
+ return new SideviewAtTimeCalculationRequest(
2307
+ data.scalarUdmOutputs,
2308
+ data.weather,
2309
+ data.dispersionRecords,
2310
+ data.dispersionRecordCount,
2311
+ data.substrate,
2312
+ data.dispersionOutputConfig,
2313
+ data.material,
2314
+ data.dispersionParameters
2315
+ );
2316
+ }
2317
+ }
2318
+
2319
+ export class SideviewAtTimeCalculation extends CalculationBase {
2320
+ scalarUdmOutputs: Entities.ScalarUdmOutputs;
2321
+ weather: Entities.Weather;
2322
+ dispersionRecords: Entities.DispersionRecord[];
2323
+ dispersionRecordCount: number;
2324
+ substrate: Entities.Substrate;
2325
+ dispersionOutputConfig: Entities.DispersionOutputConfig;
2326
+ material: Entities.Material;
2327
+ dispersionParameters: Entities.DispersionParameters;
2328
+ concUsed?: number;
2329
+ contourPoints?: Entities.LocalPosition[];
2330
+
2331
+ /**
2332
+ * Calculates the sideview of the cloud downwind from the release point and at the current averaging time.
2333
+ *
2334
+ * @param {Entities.ScalarUdmOutputs} scalarUdmOutputs - Scalar dispersion outputs.
2335
+ * @param {Entities.Weather} weather - A Weather entity.
2336
+ * @param {Entities.DispersionRecord[]} dispersionRecords - An array of Dispersion Records.
2337
+ * @param {number} dispersionRecordCount - Number of Dispersion Records.
2338
+ * @param {Entities.Substrate} substrate - A substrate entity.
2339
+ * @param {Entities.DispersionOutputConfig} dispersionOutputConfig - A Dispersion Output Config entity.
2340
+ * @param {Entities.Material} material - A Material entity with post-discharge composition.
2341
+ * @param {Entities.DispersionParameters} dispersionParameters - A Dispersion Parameters entity.
2342
+ */
2343
+ constructor(
2344
+ scalarUdmOutputs: Entities.ScalarUdmOutputs,
2345
+ weather: Entities.Weather,
2346
+ dispersionRecords: Entities.DispersionRecord[],
2347
+ dispersionRecordCount: number,
2348
+ substrate: Entities.Substrate,
2349
+ dispersionOutputConfig: Entities.DispersionOutputConfig,
2350
+ material: Entities.Material,
2351
+ dispersionParameters: Entities.DispersionParameters
2352
+ ) {
2353
+ super();
2354
+ this.scalarUdmOutputs = scalarUdmOutputs;
2355
+ this.weather = weather;
2356
+ this.dispersionRecords = dispersionRecords;
2357
+ this.dispersionRecordCount = dispersionRecordCount;
2358
+ this.substrate = substrate;
2359
+ this.dispersionOutputConfig = dispersionOutputConfig;
2360
+ this.material = material;
2361
+ this.dispersionParameters = dispersionParameters;
2362
+ }
2363
+
2364
+ async run() {
2365
+ try {
2366
+ const request = new SideviewAtTimeCalculationRequest(
2367
+ this.scalarUdmOutputs,
2368
+ this.weather,
2369
+ this.dispersionRecords,
2370
+ this.dispersionRecordCount,
2371
+ this.substrate,
2372
+ this.dispersionOutputConfig,
2373
+ this.material,
2374
+ this.dispersionParameters
2375
+ );
2376
+
2377
+ const schema = new SideviewAtTimeCalculationRequestSchema();
2378
+ const validatedRequest = schema.validate(request);
2379
+
2380
+ const requestJson = JSON.stringify(validatedRequest);
2381
+ const url = `${getAnalyticsApiTarget()}calculatesideviewattime?clientId=${getClientAliasId()}`;
2382
+
2383
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
2384
+
2385
+ const response = await this.postRequest(url, requestJson);
2386
+
2387
+ if (response.status >= 200 && response.status < 300) {
2388
+ const schema = new SideviewAtTimeCalculationResponseSchema();
2389
+ const validatedResponse = schema.validate(response.data);
2390
+
2391
+ this.resultCode = validatedResponse.resultCode;
2392
+ if (this.resultCode === Enums.ResultCode.SUCCESS) {
2393
+ this.concUsed = validatedResponse.concUsed;
2394
+ this.contourPoints = validatedResponse.contourPoints;
2395
+ this.resultCode = validatedResponse.resultCode;
2396
+ this.messages = validatedResponse.messages ?? [];
2397
+ this.calculationElapsedTime = validatedResponse.calculationElapsedTime;
2398
+ this.operationId = validatedResponse.operationId;
2399
+ } else {
2400
+ this.messages.push(...(validatedResponse.messages ?? []));
2401
+ }
2402
+ } else {
2403
+ this.handleFailedResponse(response);
2404
+ }
2405
+ } catch (error) {
2406
+ if (error instanceof Error) {
2407
+ this.messages.push(`Error: ${error.message}`);
2408
+ } else {
2409
+ this.messages.push(`Unexpected error: ${JSON.stringify(error)}`);
2410
+ }
2411
+ console.error(error);
2412
+ this.resultCode = Enums.ResultCode.UNEXPECTED_APPLICATION_ERROR;
2413
+ }
2414
+
2415
+ return this.resultCode;
2416
+ }
2417
+
2418
+ toString() {
2419
+ const parts = ["* SideviewAtTime"];
2420
+
2421
+ parts.push(`concUsed: ${String(this.concUsed)}`);
2422
+ parts.push("*** contourPoints:");
2423
+ parts.push(
2424
+ this.contourPoints && this.contourPoints.length > 0
2425
+ ? this.contourPoints.map((point) => `contourPointsElement: ${point}`).join("\n")
2426
+ : "contourPoints does not contain any elements"
2427
+ );
2428
+ parts.push(`resultCode: ${String(this.resultCode)}`);
2429
+ parts.push("*** messages:");
2430
+ parts.push(`messages: ${this.messages !== undefined ? this.messages : "(None)"}`);
2431
+ parts.push(`calculationElapsedTime: ${this.calculationElapsedTime !== undefined ? this.calculationElapsedTime : "(None)"}`);
2432
+ parts.push(`operationId: ${this.operationId !== undefined ? this.operationId : "(None)"}`);
2433
+
2434
+ return parts.join("\n");
2435
+ }
2436
+ }
2437
+
2438
+ export class SideviewAtTimeCalculationResponse extends CalculationResponseBase {
2439
+ concUsed: number;
2440
+ contourPoints: Entities.LocalPosition[];
2441
+
2442
+ /**
2443
+ * SideviewAtTime calculation response class.
2444
+ *
2445
+ * @param {number} concUsed - Concentration of interest.
2446
+ * @param {Entities.LocalPosition[]} contourPoints - An array of points along the sideview contour.
2447
+ */
2448
+ constructor(
2449
+ concUsed: number,
2450
+ contourPoints: Entities.LocalPosition[],
2451
+ resultCode: Enums.ResultCode,
2452
+ messages: string[],
2453
+ calculationElapsedTime: number,
2454
+ operationId: string
2455
+ ) {
2456
+ super();
2457
+ this.concUsed = concUsed;
2458
+ this.contourPoints = contourPoints;
2459
+ this.resultCode = resultCode;
2460
+ this.messages = messages;
2461
+ this.calculationElapsedTime = calculationElapsedTime;
2462
+ this.operationId = operationId;
2463
+ }
2464
+
2465
+ initialiseFromDictionary(data: { [key: string]: unknown }) {
2466
+ if (data.concUsed !== undefined && typeof data.concUsed === "number") {
2467
+ this.concUsed = data.concUsed as number;
2468
+ }
2469
+ if (data.contourPoints && Array.isArray(data.contourPoints)) {
2470
+ this.contourPoints = data.contourPoints.map(
2471
+ (item) => {
2472
+ const record = new Entities.LocalPosition();
2473
+ record.initialiseFromDictionary(item);
2474
+ return record;
2475
+ }
2476
+ );
2477
+ }
2478
+ if (data.resultCode !== undefined && (typeof data.resultCode === "string" || typeof data.resultCode === "number")) {
2479
+ this.resultCode = data.resultCode as Enums.ResultCode;
2480
+ }
2481
+ this.messages = this.messages ?? [];
2482
+ if (data.messages && Array.isArray(data.messages)) {
2483
+ this.messages.push(...data.messages);
2484
+ }
2485
+ if (data.calculationElapsedTime !== undefined && typeof data.calculationElapsedTime === "number") {
2486
+ this.calculationElapsedTime = data.calculationElapsedTime as number;
2487
+ }
2488
+ if (data.operationId !== undefined && typeof data.operationId === "string") {
2489
+ this.operationId = data.operationId as string;
2490
+ }
2491
+ }
2492
+ }
2493
+
2494
+ export interface SideviewAtTimeCalculationResponseSchemaData {
2495
+ concUsed: number;
2496
+ contourPoints: Entities.LocalPosition[];
2497
+ resultCode: Enums.ResultCode;
2498
+ messages: string[];
2499
+ calculationElapsedTime: number;
2500
+ operationId: string;
2501
+ }
2502
+
2503
+ export class SideviewAtTimeCalculationResponseSchema {
2504
+ schema: Joi.ObjectSchema;
2505
+ propertyTypes: Record<string, string>;
2506
+
2507
+ /**
2508
+ * Schema for the SideviewAtTime calculation response.
2509
+ */
2510
+ constructor() {
2511
+ this.schema = Joi.object({
2512
+ concUsed: Joi.number().unsafe(),
2513
+ contourPoints: Joi.array().items(new EntitySchemas.LocalPositionSchema().schema).allow(null),
2514
+ resultCode: Joi.string().valid(...Object.values(Enums.ResultCode)),
2515
+ messages: Joi.array().items(Joi.string()),
2516
+ calculationElapsedTime: Joi.number().unsafe(),
2517
+ operationId: Joi.string().uuid().allow(null),
2518
+ }).unknown(true);
2519
+
2520
+ this.propertyTypes = {
2521
+ concUsed: "number",
2522
+ contourPoints: "Entities.LocalPosition[]",
2523
+ };
2524
+ }
2525
+
2526
+ validate(data: SideviewAtTimeCalculationResponseSchemaData): SideviewAtTimeCalculationResponse {
2527
+ const { error, value } = this.schema.validate(data, { abortEarly: false });
2528
+ if (error) {
2529
+ throw new Error(`Validation error: ${error.details.map((x) => x.message).join(", ")}`);
2530
+ }
2531
+ return this.makeCalculationResponse(value);
2532
+ }
2533
+
2534
+ makeCalculationResponse(data: SideviewAtTimeCalculationResponseSchemaData): SideviewAtTimeCalculationResponse {
2535
+ return new SideviewAtTimeCalculationResponse(
2536
+ data.concUsed,
2537
+ data.contourPoints,
2538
+ data.resultCode,
2539
+ data.messages,
2540
+ data.calculationElapsedTime,
2541
+ data.operationId
2542
+ );
2543
+ }
2544
+ }