services/app.service.ts
Entrypoint to store for GM vs magnitude application.
SharedService
Properties |
|
Methods |
|
Accessors |
constructor(formBuilder: FormBuilder, nshmpService: NshmpService, spinnerService: SpinnerService, route: ActivatedRoute, location: LocationService)
|
||||||||||||||||||
Defined in services/app.service.ts:74
|
||||||||||||||||||
Parameters :
|
addValidators |
addValidators()
|
Defined in services/app.service.ts:136
|
Add validators to form controls.
Returns :
void
|
callService |
callService()
|
Defined in services/app.service.ts:165
|
Calls the Gmm distance service.
Returns :
void
|
createPlots |
createPlots()
|
Defined in services/app.service.ts:190
|
Create plots based on current state and form group.
Returns :
void
|
defaultFormValues |
defaultFormValues()
|
Defined in services/app.service.ts:199
|
Default values for control panel.
Returns :
GmmMagnitudeFormControls
|
defaultPlots |
defaultPlots()
|
Defined in services/app.service.ts:225
|
Returns the default plots.
Returns :
Map<string, NshmpPlot>
|
Private handleServiceResponses | ||||||
handleServiceResponses(serviceResponses: GmmMagnitudeResponse[])
|
||||||
Defined in services/app.service.ts:381
|
||||||
Parameters :
Returns :
void
|
Private handleUsageResponse | ||||||
handleUsageResponse(usageResponse: GmmMagnitudeUsage)
|
||||||
Defined in services/app.service.ts:408
|
||||||
Parameters :
Returns :
void
|
init |
init()
|
Defined in services/app.service.ts:298
|
Initialize the application.
Returns :
void
|
Private initialFormSet |
initialFormSet()
|
Defined in services/app.service.ts:427
|
Returns :
void
|
initialState |
initialState()
|
Defined in services/app.service.ts:316
|
GMM magnitude app inital state.
Returns :
AppState
|
resetControlPanel |
resetControlPanel()
|
Defined in services/app.service.ts:333
|
Reset the control panel.
Returns :
void
|
resetPlotSettings |
resetPlotSettings()
|
Defined in services/app.service.ts:342
|
Reset the plot settings.
Returns :
void
|
resetState |
resetState()
|
Defined in services/app.service.ts:352
|
Reset the state.
Returns :
void
|
Private serviceResponseToPlotData | ||||||||||||
serviceResponseToPlotData(state: AppState, form: FormGroupControls<GmmMagnitudeFormControls>)
|
||||||||||||
Defined in services/app.service.ts:492
|
||||||||||||
Transform Gmm distance service responses to plots.
Parameters :
Returns :
Map<string, NshmpPlot>
|
updateState | ||||||||
updateState(state: Partial<AppState>)
|
||||||||
Defined in services/app.service.ts:374
|
||||||||
Update state.
Parameters :
Returns :
void
|
Private updateUrl |
updateUrl()
|
Defined in services/app.service.ts:541
|
Returns :
void
|
Private usageFormValues | ||||||||
usageFormValues(parameters: GmmMagnitudeUsageParameters)
|
||||||||
Defined in services/app.service.ts:577
|
||||||||
Returns the default from values from parameters.
Parameters :
Returns :
GmmMagnitudeFormControls
|
Private baseUrl |
Default value : environment.webServices.gmm.url
|
Defined in services/app.service.ts:63
|
nshmp-ws base URL |
Readonly formGroup |
Default value : this.formBuilder.group({
...this.defaultFormValues(),
gmmSource: [],
MwMulti: [],
vs30Multi: [],
}) as FormGroupControls<GmmMagnitudeFormControls>
|
Defined in services/app.service.ts:67
|
Private serviceUrl |
Default value : `${this.baseUrl}${environment.webServices.gmm.services.magnitude}`
|
Defined in services/app.service.ts:65
|
GMM service URL |
Readonly state |
Default value : signal<AppState>(this.initialState())
|
Defined in services/app.service.ts:74
|
meanPlotState |
getmeanPlotState()
|
Defined in services/app.service.ts:92
|
Returns the mean plot state.
Returns :
Signal<NshmpPlot>
|
serviceCallInfo |
getserviceCallInfo()
|
Defined in services/app.service.ts:99
|
Returns service call info observable.
Returns :
Signal<ServiceCallInfo>
|
serviceResponse |
getserviceResponse()
|
Defined in services/app.service.ts:106
|
Returns the Gmm distance service responses.
Returns :
Signal<GmmMagnitudeResponse[]>
|
sigmaPlotState |
getsigmaPlotState()
|
Defined in services/app.service.ts:113
|
Returns the mean plot state.
Returns :
Signal<NshmpPlot>
|
supportedImts |
getsupportedImts()
|
Defined in services/app.service.ts:120
|
Returns supported IMTs observable.
Returns :
Signal<EnumParameterValues[]>
|
usage |
getusage()
|
Defined in services/app.service.ts:127
|
Returns the Gmm distance usage response.
Returns :
Signal<GmmMagnitudeUsage>
|
import {Location as LocationService} from '@angular/common';
import {HttpParams} from '@angular/common/http';
import {computed, Injectable, Signal, signal} from '@angular/core';
import {AbstractControl, FormBuilder, Validators} from '@angular/forms';
import {ActivatedRoute} from '@angular/router';
import {
GmmAppQueryImt,
gmmUtils,
MultiSelectableParam,
} from '@ghsc/nshmp-lib-ng/gmm';
import {
FormGroupControls,
NshmpService,
nshmpUtils,
ServiceCallInfo,
SpinnerService,
} from '@ghsc/nshmp-lib-ng/nshmp';
import {
NshmpPlot,
NshmpPlotSettings,
PlotOptions,
plotUtils,
} from '@ghsc/nshmp-lib-ng/plot';
import {XySequence} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/data';
import {
GmmGroupType,
GmmMagnitudeResponse,
GmmMagnitudeUsage,
GmmMagnitudeUsageParameters,
} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws/gmm-services';
import {EnumParameterValues} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils/metadata';
import {environment} from 'projects/nshmp-apps/src/environments/environment';
import {AppServiceModel} from 'projects/nshmp-apps/src/shared/models/app-service.model';
import {SharedService} from 'projects/nshmp-apps/src/shared/services/shared.service';
import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
import {catchError} from 'rxjs';
import {GmmMagnitudeFormControls} from '../models/gmm-magnitude-form-controls.model';
import {AppState} from '../models/state.model';
interface Query extends GmmAppQueryImt {
/** Distance */
distance: string;
/** Max magnitude */
mMax: string;
/** Min magnitude */
mMin: string;
/** Magnitude step */
step: string;
}
/**
* Entrypoint to store for GM vs magnitude application.
*/
@Injectable({
providedIn: 'root',
})
export class AppService
extends SharedService
implements AppServiceModel<AppState, GmmMagnitudeFormControls>
{
/** nshmp-ws base URL */
private baseUrl = environment.webServices.gmm.url;
/** GMM service URL */
private serviceUrl = `${this.baseUrl}${environment.webServices.gmm.services.magnitude}`;
readonly formGroup = this.formBuilder.group({
...this.defaultFormValues(),
gmmSource: [],
MwMulti: [],
vs30Multi: [],
}) as FormGroupControls<GmmMagnitudeFormControls>;
readonly state = signal<AppState>(this.initialState());
constructor(
private formBuilder: FormBuilder,
private nshmpService: NshmpService,
private spinnerService: SpinnerService,
private route: ActivatedRoute,
private location: LocationService,
) {
super();
this.addValidators();
this.formGroup.controls.gmmSource.setValue([]);
this.formGroup.controls.showEpistemicUncertainty.disable();
}
/**
* Returns the mean plot state.
*/
get meanPlotState(): Signal<NshmpPlot> {
return computed(() => this.state().plots?.get(gmmUtils.PlotType.MEANS));
}
/**
* Returns service call info observable.
*/
get serviceCallInfo(): Signal<ServiceCallInfo> {
return computed(() => this.state().serviceCallInfo);
}
/**
* Returns the Gmm distance service responses.
*/
get serviceResponse(): Signal<GmmMagnitudeResponse[]> {
return computed(() => this.state().serviceResponses);
}
/**
* Returns the mean plot state.
*/
get sigmaPlotState(): Signal<NshmpPlot> {
return computed(() => this.state().plots?.get(gmmUtils.PlotType.SIGMA));
}
/**
* Returns supported IMTs observable.
*/
get supportedImts(): Signal<EnumParameterValues[]> {
return computed(() => this.state().supportedImts);
}
/**
* Returns the Gmm distance usage response.
*/
get usage(): Signal<GmmMagnitudeUsage> {
return computed(() => this.state().usageResponse);
}
/**
* Add validators to form controls.
*
* @param form The form group
*/
addValidators(): void {
const required = (control: AbstractControl) => Validators.required(control);
this.formGroup.controls.Mw.addValidators(required);
this.formGroup.controls.dip.addValidators(required);
this.formGroup.controls.gmmSource.addValidators(required);
this.formGroup.controls.imt.addValidators(required);
this.formGroup.controls.multiSelectableParam.addValidators(required);
this.formGroup.controls.vs30.addValidators(required);
this.formGroup.controls.width.addValidators(required);
this.formGroup.controls.zTor.addValidators(required);
this.formGroup.controls.vs30Multi.addValidators(control => {
if (
this.formGroup.getRawValue().multiSelectableParam ===
MultiSelectableParam.VS30
) {
return Validators.required(control);
} else {
return Validators.nullValidator(control);
}
});
this.formGroup.updateValueAndValidity();
}
/**
* Calls the Gmm distance service.
*/
callService(): void {
if (this.formGroup.invalid) {
return;
}
const spinnerRef = this.spinnerService.show(SpinnerService.MESSAGE_SERVICE);
const urls = gmmUtils.serviceEndpoints(
this.serviceUrl,
this.formGroup.getRawValue(),
this.formGroup.getRawValue().multiSelectableParam,
);
this.nshmpService
.callServices$<GmmMagnitudeResponse>(urls)
.pipe(catchError((error: Error) => this.nshmpService.throwError$(error)))
.subscribe(serviceResponses => {
this.handleServiceResponses(serviceResponses);
spinnerRef.close();
});
}
/**
* Create plots based on current state and form group.
*/
createPlots(): void {
this.updateState({
plots: this.serviceResponseToPlotData(this.state(), this.formGroup),
});
}
/**
* Default values for control panel.
*/
defaultFormValues(): GmmMagnitudeFormControls {
return {
dip: null,
distance: null,
gmmGroupType: GmmGroupType.ACTIVE_CRUST,
gmmSource: [],
imt: 'default',
mMax: null,
mMin: null,
multiSelectableParam: MultiSelectableParam.GMM,
Mw: null,
showEpistemicUncertainty: false,
step: null,
vs30: null,
vs30Multi: [],
width: null,
z1p0: null,
z2p5: null,
zSed: null,
zTor: null,
};
}
/**
* Returns the default plots.
*/
defaultPlots(): Map<string, NshmpPlot> {
const plots = new Map<string, NshmpPlot>();
const plotOptions: PlotOptions = {
layout: {
xaxis: {
nticks: 10,
range: [Math.log10(5), Math.log10(8)],
},
yaxis: {
range: [Math.log10(0.001), Math.log10(3)],
},
},
};
const meanPlotData = plotUtils.defaultPlot({
id: gmmUtils.PlotType.MEANS,
mobileOptions: {...plotOptions},
options: {
...plotOptions,
layout: {
aspectRatio: gmmUtils.MEAN_ASPECT_RATIO,
...plotOptions.layout,
},
},
title: 'Ground Motion vs. Magnitude',
xLabel: 'Magnitude',
yLabel: 'Median ground motion (g)',
});
const sigmaPlotData = plotUtils.defaultPlot({
id: gmmUtils.PlotType.SIGMA,
mobileOptions: {...plotOptions},
options: {
...plotOptions,
layout: {
aspectRatio: gmmUtils.MEAN_ASPECT_RATIO,
...plotOptions.layout,
},
},
title: 'Standard Deviation',
xLabel: 'Magnitude',
yLabel: 'Standard deviation',
});
/** Default mean settings */
const meanSettingsForm: NshmpPlotSettings = {
config: meanPlotData.config,
layout: plotUtils.plotlyLayoutToSettings(meanPlotData.layout),
};
/** Default sigma settings */
const sigmaSettingsForm: NshmpPlotSettings = {
config: sigmaPlotData.config,
layout: plotUtils.plotlyLayoutToSettings(sigmaPlotData.layout),
};
plots.set(gmmUtils.PlotType.MEANS, {
label: 'Response Spectra',
plotData: meanPlotData,
settingsForm: plotUtils.plotSettingsToFormGroup(meanSettingsForm),
});
plots.set(gmmUtils.PlotType.SIGMA, {
label: 'Standard Deviation',
plotData: sigmaPlotData,
settingsForm: plotUtils.plotSettingsToFormGroup(sigmaSettingsForm),
});
return new Map(plots);
}
/**
* Initialize the application.
*/
init(): void {
const spinnerRef = this.spinnerService.show(
SpinnerService.MESSAGE_METADATA,
);
this.nshmpService
.callService$<GmmMagnitudeUsage>(this.serviceUrl)
.pipe(catchError((error: Error) => this.nshmpService.throwError$(error)))
.subscribe(usageResponse => {
this.handleUsageResponse(usageResponse);
this.initialFormSet();
spinnerRef.close();
});
}
/**
* GMM magnitude app inital state.
*/
initialState(): AppState {
return {
plots: this.defaultPlots(),
serviceCallInfo: {
serviceCalls: [],
serviceName: 'Ground Motion vs. Magnitude',
usage: [],
},
serviceResponses: [],
supportedImts: [],
usageResponse: null,
};
}
/**
* Reset the control panel.
*/
resetControlPanel(): void {
this.formGroup.reset(
this.usageFormValues(this.state().usageResponse.response.parameters),
);
}
/**
* Reset the plot settings.
*/
resetPlotSettings(): void {
super.resetPlotSettings({
currentPlots: this.state().plots,
defaultPlots: this.defaultPlots(),
});
}
/**
* Reset the state.
*/
resetState(): void {
const serviceCallInfo = gmmUtils.serviceCallInfo({
multiSelectableParam: this.formGroup.getRawValue().multiSelectableParam,
serviceName: this.state().serviceCallInfo.serviceName,
serviceResponses: this.state().serviceResponses,
serviceUrl: this.serviceUrl,
values: this.formGroup.getRawValue(),
});
this.updateState({
serviceCallInfo,
serviceResponses: null,
});
this.createPlots();
}
/**
* Update state.
*
* @param state Partial new state to update
*/
updateState(state: Partial<AppState>): void {
this.state.set({
...this.state(),
...state,
});
}
private handleServiceResponses(
serviceResponses: GmmMagnitudeResponse[],
): void {
const means = serviceResponses.map(s => s.response.means);
const sigmas = serviceResponses.map(s => s.response.sigmas);
const hasLogicTree = gmmUtils.hasTree([...means, ...sigmas]);
if (hasLogicTree) {
this.formGroup.controls.showEpistemicUncertainty.enable();
} else {
this.formGroup.controls.showEpistemicUncertainty.disable();
}
this.updateState({
serviceCallInfo: gmmUtils.serviceCallInfo({
multiSelectableParam: this.formGroup.getRawValue().multiSelectableParam,
serviceName: this.state().serviceCallInfo.serviceName,
serviceResponses,
serviceUrl: this.serviceUrl,
values: this.formGroup.getRawValue(),
}),
serviceResponses,
});
this.createPlots();
}
private handleUsageResponse(usageResponse: GmmMagnitudeUsage): void {
const parameters = usageResponse.response.parameters;
const values = this.usageFormValues(parameters);
this.formGroup.patchValue({
...values,
});
const serviceCallInfo: ServiceCallInfo = {
...this.state().serviceCallInfo,
usage: [this.serviceUrl],
};
this.updateState({
serviceCallInfo,
usageResponse,
});
}
private initialFormSet(): void {
const query = this.route.snapshot.queryParams as Query;
const defaultValues = this.formGroup.getRawValue();
const parameters = this.usage().response.parameters;
const gmmSource = gmmUtils.queryToGmmSource(query.gmm, parameters);
this.formGroup.patchValue({
multiSelectableParam:
query?.multiSelectableParam ?? defaultValues.multiSelectableParam,
});
this.formGroup.patchValue({
dip: nshmpUtils.queryParseNumber(defaultValues.dip, query?.dip),
distance: nshmpUtils.queryParseNumber(
defaultValues.distance,
query?.distance,
),
gmmGroupType: query?.gmmGroupType ?? defaultValues.gmmGroupType,
gmmSource,
imt: query?.imt ?? defaultValues.imt,
mMax: query?.mMax ? Number.parseFloat(query.mMax) : defaultValues.mMax,
mMin: query?.mMin ? Number.parseFloat(query.mMin) : defaultValues.mMin,
Mw: nshmpUtils.queryParseNumber(defaultValues.Mw, query?.Mw),
MwMulti: nshmpUtils
.queryStringToArray(query?.MwMulti)
.map(mw => Number.parseFloat(mw)),
showEpistemicUncertainty: nshmpUtils.queryParseBoolean(
defaultValues.showEpistemicUncertainty,
query?.showEpistemicUncertainty,
),
step: nshmpUtils.queryParseNumber(defaultValues.step, query?.step),
vs30: nshmpUtils.queryParseNumber(defaultValues.vs30, query?.vs30),
vs30Multi: nshmpUtils
.queryStringToArray(query?.vs30Multi)
.map(vs30 => Number.parseFloat(vs30)),
width: nshmpUtils.queryParseNumber(defaultValues.width, query?.width),
z1p0: nshmpUtils.queryParseNumber(defaultValues.z1p0, query?.z1p0),
z2p5: nshmpUtils.queryParseNumber(defaultValues.z2p5, query?.z2p5),
zSed: nshmpUtils.queryParseNumber(defaultValues.zSed, query?.zSed),
zTor: nshmpUtils.queryParseNumber(defaultValues.zTor, query?.zTor),
});
if (
this.formGroup.value.multiSelectableParam === MultiSelectableParam.VS30
) {
this.formGroup.patchValue({
gmmSource: gmmSource.length > 0 ? [gmmSource.pop()] : [],
});
}
if (this.formGroup.valid) {
this.callService();
} else {
this.formGroup.markAsDirty();
}
this.formGroup.valueChanges.subscribe(() => this.updateUrl());
}
/**
* Transform Gmm distance service responses to plots.
*
* @param state The application state
*/
private serviceResponseToPlotData(
state: AppState,
form: FormGroupControls<GmmMagnitudeFormControls>,
): Map<string, NshmpPlot> {
if (
state.serviceResponses === null ||
state.serviceResponses?.length === 0
) {
return this.defaultPlots();
}
const plots = new Map<string, NshmpPlot>();
const meanPlot = state.plots.get(gmmUtils.PlotType.MEANS);
const sigmaPlot = state.plots.get(gmmUtils.PlotType.SIGMA);
const formValues = form.getRawValue();
const responses: gmmUtils.GmmResponse<XySequence, number[]>[] =
state.serviceResponses.map(serviceResponse => ({
input: serviceResponse.request.input,
meanPlotConfig: {
hoverTemplate: '%{x} Mw, %{y} g',
},
response: serviceResponse.response,
sigmaPlotConfig: {
hoverTemplate: '%{x} Mw, %{y} 𝞂',
},
}));
const gmmPlots = gmmUtils.gmmResponsesToPlots({
meanPlot,
multiSelectableParam: formValues.multiSelectableParam,
responses,
showEpistemicUncertainty: formValues.showEpistemicUncertainty,
sigmaPlot,
});
plots.set(gmmUtils.PlotType.MEANS, {
...meanPlot,
plotData: gmmPlots.means,
});
plots.set(gmmUtils.PlotType.SIGMA, {
...sigmaPlot,
plotData: gmmPlots.sigmas,
});
return plots;
}
private updateUrl(): void {
const value = this.formGroup.getRawValue();
const query: Query = {
dip: value.dip?.toString(),
distance: value.distance?.toString(),
gmm: gmmUtils.gmmSourceToQuery(value.gmmSource),
gmmGroupType: value.gmmGroupType,
imt: value.imt,
mMax: value.mMax?.toString(),
mMin: value.mMin?.toString(),
multiSelectableParam: value.multiSelectableParam,
Mw: value.Mw?.toString(),
MwMulti: value.MwMulti?.map(mw => mw.toString()),
showEpistemicUncertainty: value.showEpistemicUncertainty.toString(),
step: value.step?.toString(),
vs30: value.vs30?.toString(),
vs30Multi: value.vs30Multi?.map(vs30 => vs30.toString()),
width: value.width?.toString(),
z1p0: value.z1p0?.toString(),
z2p5: value.z2p5?.toString(),
zSed: value.zSed?.toString(),
zTor: value.zTor?.toString(),
};
this.location.replaceState(
apps().gmm.magnitude.routerLink,
new HttpParams().appendAll({...query}).toString(),
);
}
/**
* Returns the default from values from parameters.
*
* @param parameters The service parameters
*/
private usageFormValues(
parameters: GmmMagnitudeUsageParameters,
): GmmMagnitudeFormControls {
return {
...this.defaultFormValues(),
dip: parameters.dip.value as number,
distance: parameters.distance.value as number,
mMax: parameters.mMax.value as number,
mMin: parameters.mMin.value as number,
Mw: parameters.Mw.value as number,
step: parameters.step.value as number,
vs30: parameters.vs30.value as number,
width: parameters.width.value as number,
z1p0: parameters.z1p0.value as number,
z2p5: parameters.z2p5.value as number,
zTor: parameters.zTor.value as number,
};
}
}