services/app.service.ts
Entrypoint to store for MFD application.
SharedService
Properties |
|
Methods |
|
Accessors |
constructor(formBuilder: FormBuilder, spinnerService: SpinnerService, nshmpService: NshmpService, hazardService: HazardService, route: ActivatedRoute, location: LocationService)
|
|||||||||||||||||||||
Defined in services/app.service.ts:106
|
|||||||||||||||||||||
Parameters :
|
Private addRequiredValidator | ||||||
addRequiredValidator(control: AbstractControl)
|
||||||
Defined in services/app.service.ts:537
|
||||||
Parameters :
Returns :
void
|
addValidators |
addValidators()
|
Defined in services/app.service.ts:187
|
Returns :
void
|
callService |
callService()
|
Defined in services/app.service.ts:198
|
Call MFD services.
Returns :
void
|
createPlots |
createPlots()
|
Defined in services/app.service.ts:231
|
Returns :
void
|
Private createServiceEndpoint | |||||||||
createServiceEndpoint(serviceUrl: string, values: ControlForm)
|
|||||||||
Defined in services/app.service.ts:541
|
|||||||||
Parameters :
Returns :
string
|
defaultFormValues |
defaultFormValues()
|
Defined in services/app.service.ts:251
|
Returns the default control panel form field values.
Returns :
ControlForm
|
defaultPlots |
defaultPlots()
|
Defined in services/app.service.ts:271
|
Returns the default plots.
Returns :
Map<string, NshmpPlot>
|
defaultSource | ||||||||
defaultSource(trees: SettingGroup[])
|
||||||||
Defined in services/app.service.ts:369
|
||||||||
Return the feault source to use from settings groups.
Parameters :
Returns :
MfdSource
|
defaultSourceTree | ||||||||||||
defaultSourceTree(trees: SettingGroup[], source: MfdSource)
|
||||||||||||
Defined in services/app.service.ts:388
|
||||||||||||
Returns the default source tree to use from the settings group and MFD source.
Parameters :
Returns :
TreeInfo
|
filterMfds | ||||||||||||
filterMfds(mfds: MfdBranch[], type: MfdType)
|
||||||||||||
Defined in services/app.service.ts:406
|
||||||||||||
Filter MFD based on current MfdType.
Parameters :
Returns :
MfdBranch[]
|
Private findSettingsGroup | ||||||||||||
findSettingsGroup(trees: SettingGroup[], source: MfdSource)
|
||||||||||||
Defined in services/app.service.ts:555
|
||||||||||||
Return the matching setting group from a MfdSource.
Parameters :
Returns :
SettingGroup
|
Private findSourceGroup | ||||||||||||
findSourceGroup(trees: SettingGroup[], source: MfdSource)
|
||||||||||||
Defined in services/app.service.ts:569
|
||||||||||||
Parameters :
Returns :
SourceGroup
|
findTreeInfo | ||||||||||||||||
findTreeInfo(trees: SettingGroup[], source: MfdSource, id: number)
|
||||||||||||||||
Defined in services/app.service.ts:425
|
||||||||||||||||
Retrurn the matching tree from MFD source and source tree id.
Parameters :
Returns :
TreeInfo
|
init |
init()
|
Defined in services/app.service.ts:433
|
Initialize the application.
Returns :
void
|
Private initialFormSet |
initialFormSet()
|
Defined in services/app.service.ts:577
|
Returns :
void
|
initialState |
initialState()
|
Defined in services/app.service.ts:466
|
Application initial state.
Returns :
AppState
|
Private logicTreeByMfdBranch | ||||||||||||||||||||
logicTreeByMfdBranch(logicTreeData: LogicTreeData, branch: SourceBranch, parent: string, type: MfdType)
|
||||||||||||||||||||
Defined in services/app.service.ts:634
|
||||||||||||||||||||
Add logic tree data by MFD branch.
Parameters :
Returns :
void
|
Private logicTreeByType | ||||||||||||||||
logicTreeByType(logicTreeData: LogicTreeData, branch: SourceBranch, parent: string)
|
||||||||||||||||
Defined in services/app.service.ts:666
|
||||||||||||||||
Add logic tree data by type.
Parameters :
Returns :
void
|
Private logicTreeData | ||||||||
logicTreeData(serviceResponse: SourceLogicTreesResponse)
|
||||||||
Defined in services/app.service.ts:693
|
||||||||
Create the logic tree data from service response.
Parameters :
Returns :
LogicTreeData
|
resetControlPanel |
resetControlPanel()
|
Defined in services/app.service.ts:487
|
Reset the control panel.
Returns :
void
|
resetSettings |
resetSettings()
|
Defined in services/app.service.ts:495
|
Reset the plot settings.
Returns :
void
|
resetState |
resetState()
|
Defined in services/app.service.ts:502
|
Returns :
void
|
Private responseToPlots | ||||||||||||
responseToPlots(state: AppState, formGroup: FormGroupControls<ControlForm>)
|
||||||||||||
Defined in services/app.service.ts:727
|
||||||||||||
Create the application plots from the MFD service response.
Parameters :
Returns :
Map<string, NshmpPlot>
|
Private setLogicTreePlotData | ||||||||||||
setLogicTreePlotData(serviceResponse: SourceLogicTreesResponse, plot: NshmpPlot)
|
||||||||||||
Defined in services/app.service.ts:767
|
||||||||||||
Returns the logic tree plot data.
Parameters :
Returns :
PlotlyPlot
|
Private setMfdPlotData | ||||||||||||||||
setMfdPlotData(serviceResponse: SourceLogicTreesResponse, plot: NshmpPlot, form: ControlForm)
|
||||||||||||||||
Defined in services/app.service.ts:797
|
||||||||||||||||
Returns the MFD plot data.
Parameters :
Returns :
PlotlyPlot
|
updateState | ||||||
updateState(state: Partial<AppState>)
|
||||||
Defined in services/app.service.ts:523
|
||||||
Parameters :
Returns :
void
|
Private updateUrl |
updateUrl()
|
Defined in services/app.service.ts:895
|
Returns :
void
|
Private updateUsageUrl |
updateUsageUrl()
|
Defined in services/app.service.ts:915
|
Returns :
void
|
Readonly formGroup |
Default value : this.formBuilder.group<ControlForm>(
this.defaultFormValues(),
)
|
Defined in services/app.service.ts:101
|
Private nshmpHazWs |
Default value : environment.webServices.nshmpHazWs
|
Defined in services/app.service.ts:95
|
nshmp-haz-ws web config |
Private serviceEndpoint |
Default value : this.nshmpHazWs.services.curveServices.mfds
|
Defined in services/app.service.ts:97
|
Hazard endpoint |
Readonly state |
Default value : signal<AppState>(this.initialState())
|
Defined in services/app.service.ts:106
|
Application state |
Private usageEndpoint |
Default value : this.nshmpHazWs.services.curveServices.trees
|
Defined in services/app.service.ts:99
|
Usage endpoint |
availableModels |
getavailableModels()
|
Defined in services/app.service.ts:128
|
Returns the available models.
Returns :
Signal<Parameter[]>
|
logicTreePlotData |
getlogicTreePlotData()
|
Defined in services/app.service.ts:135
|
Returns the logic tree plot data observable.
Returns :
Signal<PlotlyPlot>
|
mfdPlotData |
getmfdPlotData()
|
Defined in services/app.service.ts:142
|
Returns the hazard plot data.
Returns :
Signal<PlotlyPlot>
|
mfdPlotSettings |
getmfdPlotSettings()
|
Defined in services/app.service.ts:149
|
Returns the hazard plot settings form.
Returns :
Signal<FormGroup<NshmpPlotSettingFormGroup>>
|
mfdPlotState |
getmfdPlotState()
|
Defined in services/app.service.ts:156
|
Returns the hazard plot.
Returns :
Signal<NshmpPlot>
|
plots |
getplots()
|
Defined in services/app.service.ts:160
|
serviceCallInfo |
getserviceCallInfo()
|
Defined in services/app.service.ts:167
|
Returns the service call info.
Returns :
Signal<ServiceCallInfo>
|
serviceResponse |
getserviceResponse()
|
Defined in services/app.service.ts:174
|
Returns the disagg response.
Returns :
Signal<SourceLogicTreesResponse>
|
usage |
getusage()
|
Defined in services/app.service.ts:181
|
Returns the MFD usage response observable.
Returns :
Signal<SourceLogicTreesUsage>
|
import {Location as LocationService} from '@angular/common';
import {HttpParams} from '@angular/common/http';
import {computed, Injectable, Signal, signal} from '@angular/core';
import {
AbstractControl,
FormBuilder,
FormGroup,
Validators,
} from '@angular/forms';
import {ActivatedRoute} from '@angular/router';
import {HazardService, hazardUtils} from '@ghsc/nshmp-lib-ng/hazard';
import {
FormGroupControls,
NshmpService,
ServiceCallInfo,
SpinnerService,
} from '@ghsc/nshmp-lib-ng/nshmp';
import {
NshmpPlot,
NshmpPlotSettingFormGroup,
PlotOptions,
plotUtils,
} from '@ghsc/nshmp-lib-ng/plot';
import {
SourceLogicTreesMetadata,
SourceLogicTreesResponse,
SourceLogicTreesUsage,
} from '@ghsc/nshmp-utils-ts/libs/nshmp-haz/www/source-logic-trees-service';
import {Sequences} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/data';
import {
MfdBranch,
SettingGroup,
SourceBranch,
SourceGroup,
SourceType,
TectonicSettings,
TreeInfo,
} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/model';
import {NshmId} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/nshm';
import {Parameter} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils/metadata';
import {PlotlyPlot} from '@ghsc/nshmp-utils-ts/libs/plotly';
import deepEqual from 'deep-equal';
import {PlotData} from 'plotly.js';
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/operators';
import {ControlForm, MfdSource, MfdType} from '../models/control-form.model';
import {Plots} from '../models/plots.model';
import {AppState} from '../models/state.model';
/**
* Logic tree data
*/
interface LogicTreeData {
/** Logic tree labels */
labels: string[];
/** Logic tree parents */
parents: string[];
/** Logic tree text */
text: string[];
}
/**
* URL query parameters.
*/
export interface MfdQuery {
/** Cumulative series */
cumulative: string;
/** NSHm */
model: NshmId;
/** Tectonic settings */
setting: TectonicSettings;
/** Source tree id number */
sourceTree: string;
/** Source type */
sourceType: SourceType;
/** Whether to apply weight */
weightedMfds: string;
}
/**
* Entrypoint to store for MFD application.
*/
@Injectable({
providedIn: 'root',
})
export class AppService
extends SharedService
implements AppServiceModel<AppState, ControlForm>
{
/** nshmp-haz-ws web config */
private nshmpHazWs = environment.webServices.nshmpHazWs;
/** Hazard endpoint */
private serviceEndpoint = this.nshmpHazWs.services.curveServices.mfds;
/** Usage endpoint */
private usageEndpoint = this.nshmpHazWs.services.curveServices.trees;
readonly formGroup = this.formBuilder.group<ControlForm>(
this.defaultFormValues(),
);
/** Application state */
readonly state = signal<AppState>(this.initialState());
constructor(
private formBuilder: FormBuilder,
private spinnerService: SpinnerService,
private nshmpService: NshmpService,
private hazardService: HazardService,
private route: ActivatedRoute,
private location: LocationService,
) {
super();
this.formGroup.controls.mfdType.disable();
this.addValidators();
this.formGroup.controls.source.setValue(this.defaultFormValues().source);
}
/**
* Returns the available dynamic models observable.
*/
/**
* Returns the available models.
*/
get availableModels(): Signal<Parameter[]> {
return computed(() => this.state().availableModels);
}
/**
* Returns the logic tree plot data observable.
*/
get logicTreePlotData(): Signal<PlotlyPlot> {
return computed(() => this.state().plots.get(Plots.LOGIC_TREE).plotData);
}
/**
* Returns the hazard plot data.
*/
get mfdPlotData(): Signal<PlotlyPlot> {
return computed(() => this.mfdPlotState().plotData);
}
/**
* Returns the hazard plot settings form.
*/
get mfdPlotSettings(): Signal<FormGroup<NshmpPlotSettingFormGroup>> {
return computed(() => this.mfdPlotState().settingsForm);
}
/**
* Returns the hazard plot.
*/
get mfdPlotState(): Signal<NshmpPlot> {
return computed(() => this.state().plots.get(Plots.MFD));
}
get plots(): Signal<Map<string, NshmpPlot>> {
return computed(() => this.state().plots);
}
/**
* Returns the service call info.
*/
get serviceCallInfo(): Signal<ServiceCallInfo> {
return computed(() => this.state().serviceCallInfo);
}
/**
* Returns the disagg response.
*/
get serviceResponse(): Signal<SourceLogicTreesResponse> {
return computed(() => this.state().serviceResponse);
}
/**
* Returns the MFD usage response observable.
*/
get usage(): Signal<SourceLogicTreesUsage> {
return computed(() =>
this.state().usageResponses?.get(this.formGroup.getRawValue().model),
);
}
addValidators(): void {
const controls = this.formGroup.controls;
this.addRequiredValidator(controls.model);
this.addRequiredValidator(controls.source);
this.addRequiredValidator(controls.sourceTree);
}
/**
* Call MFD services.
*/
callService(): void {
const spinnerRef = this.spinnerService.show(SpinnerService.MESSAGE_SERVICE);
const values = this.formGroup.getRawValue();
const service = this.state().nshmServices.find(
nshmService => nshmService.model === values.model,
);
const serviceUrl = `${service.url}${this.serviceEndpoint}`;
const url = this.createServiceEndpoint(serviceUrl, values);
this.nshmpService
.callService$<SourceLogicTreesResponse>(url)
.pipe(
catchError((error: Error) => {
spinnerRef.close();
return this.nshmpService.throwError$(error);
}),
)
.subscribe(serviceResponse => {
spinnerRef.close();
this.updateState({
serviceCallInfo: {
...this.state().serviceCallInfo,
serviceCalls: [url],
},
serviceResponse,
});
this.createPlots();
});
}
createPlots(): void {
if (this.state().serviceResponse === null) {
return;
}
if (this.formGroup.getRawValue().mfdType === null) {
this.formGroup.controls.mfdType.setValue(MfdType.ALL);
}
if (this.formGroup.controls.mfdType.disabled) {
this.formGroup.controls.mfdType.enable();
}
const plots = this.responseToPlots(this.state(), this.formGroup);
this.updateState({plots});
}
/**
* Returns the default control panel form field values.
*/
defaultFormValues(): ControlForm {
const source: MfdSource = {
sourceType: SourceType.FAULT,
tectonicSettings: TectonicSettings.ACTIVE_CRUST,
};
return {
cumulative: false,
mfdType: null,
model: NshmId.CONUS_2018,
source,
sourceAsString: JSON.stringify(source),
sourceTree: null,
weightedMfds: false,
};
}
/**
* Returns the default plots.
*/
defaultPlots(): Map<string, NshmpPlot> {
const plots = new Map<string, NshmpPlot>();
const logicTreeOptions: PlotOptions = {
layout: {
aspectRatio: undefined,
margin: {
b: 10,
l: 10,
r: 10,
},
},
};
const plotOptions: PlotOptions = {
layout: {
xaxis: {
nticks: 10,
range: [6.5, 7.7],
type: 'linear',
},
yaxis: {
type: 'log',
},
},
};
/** Default logic tree plot data */
const logicTreePlotData: PlotlyPlot = {
...plotUtils.defaultPlot({
id: 'mfd-logic-tree',
mobileOptions: {...logicTreeOptions},
options: {...logicTreeOptions},
title: 'MFD Logic Tree',
xLabel: '',
yLabel: '',
}),
data: [
{
labels: ['Logic Tree Branches'],
parents: [''],
type: 'treemap',
},
],
};
/** Default MFD plot data */
const mfdPlotData = plotUtils.defaultPlot({
id: 'mfd-plot',
mobileOptions: {
...plotOptions,
layout: {
...plotOptions.layout,
aspectRatio: '1:1',
},
},
options: {
...plotOptions,
layout: {
...plotOptions.layout,
legend: {
font: {
size: 11,
},
},
},
},
title: 'Magnitude Frequency Distribution',
xLabel: 'Magnitude',
yLabel: 'Rate (yr<sup>-1</sup>)',
});
plots.set(Plots.MFD, {
label: 'MFD',
plotData: mfdPlotData,
settingsForm: plotUtils.plotSettingsToFormGroup({
config: mfdPlotData.config,
layout: plotUtils.plotlyLayoutToSettings(mfdPlotData.layout),
}),
});
plots.set(Plots.LOGIC_TREE, {
label: Plots.LOGIC_TREE,
plotData: logicTreePlotData,
settingsForm: plotUtils.plotSettingsToFormGroup({
config: logicTreePlotData.config,
layout: plotUtils.plotlyLayoutToSettings(logicTreePlotData.layout),
}),
});
return plots;
}
/**
* Return the feault source to use from settings groups.
*
* @param trees Settings groups
*/
defaultSource(trees: SettingGroup[]): MfdSource {
const defaultTree = [
...trees.sort((a, b) => a.setting.localeCompare(b.setting)),
].shift();
return {
sourceType: [
...defaultTree.data.sort((a, b) => a.type.localeCompare(b.type)),
].shift().type,
tectonicSettings: defaultTree.setting,
};
}
/**
* Returns the default source tree to use from the settings group and MFD source.
*
* @param trees The settings groups
* @param source MFD source
*/
defaultSourceTree(trees: SettingGroup[], source: MfdSource): TreeInfo {
const settingsTree = [...trees].find(
tree => tree.setting === source.tectonicSettings,
);
const tree = settingsTree.data.find(
data => data.type === source.sourceType,
);
return [...tree.data.sort((a, b) => a.name.localeCompare(b.name))].shift();
}
/**
* Filter MFD based on current {@link MfdType}.
*
* @param mfds The MFD branches
* @param type The MFD type
*/
filterMfds(mfds: MfdBranch[], type: MfdType): MfdBranch[] {
return mfds
.filter(mfdInfo => {
if (type === MfdType.ALL) {
return mfdInfo;
} else if (mfdInfo.mfd.props.type === type) {
return mfdInfo;
}
})
.sort((a, b) => a.mfd.props.type.localeCompare(b.mfd.props.type));
}
/**
* Retrurn the matching tree from MFD source and source tree id.
*
* @param trees The settings groups
* @param source The MFD source
* @param id The source tree id number
*/
findTreeInfo(trees: SettingGroup[], source: MfdSource, id: number): TreeInfo {
const sourceGroup = this.findSourceGroup(trees, source);
return sourceGroup.data.find(data => data.id === id);
}
/**
* Initialize the application.
*/
init(): void {
const spinnerRef = this.spinnerService.show(
SpinnerService.MESSAGE_METADATA,
);
this.hazardService
.dynamicNshms$<SourceLogicTreesMetadata>(
`${this.nshmpHazWs.url}${this.nshmpHazWs.services.nshms}`,
this.usageEndpoint,
)
.pipe(
catchError((error: Error) => {
spinnerRef.close();
return this.nshmpService.throwError$(error);
}),
)
.subscribe(({models, nshmServices, usageResponses}) => {
spinnerRef.close();
this.updateState({
availableModels: models,
nshmServices,
usageResponses,
});
this.updateUsageUrl();
this.initialFormSet();
});
}
/**
* Application initial state.
*/
initialState(): AppState {
const usageResponses: Map<string, SourceLogicTreesUsage> = new Map();
usageResponses.set(NshmId.CONUS_2018, null);
return {
availableModels: [],
nshmServices: [],
plots: this.defaultPlots(),
serviceCallInfo: {
serviceCalls: [],
serviceName: 'Hazard Source Trees',
usage: [],
},
serviceResponse: null,
usageResponses,
};
}
/**
* Reset the control panel.
*/
resetControlPanel(): void {
this.formGroup.reset(this.defaultFormValues());
this.resetState();
}
/**
* Reset the plot settings.
*/
resetSettings(): void {
super.resetPlotSettings({
currentPlots: this.state().plots,
defaultPlots: this.initialState().plots,
});
}
resetState(): void {
this.updateState({
plots: this.initialState().plots,
serviceCallInfo: {
...this.state().serviceCallInfo,
serviceCalls: [],
},
serviceResponse: null,
});
if (this.formGroup.controls.mfdType.enabled) {
this.formGroup.controls.mfdType.disable();
}
if (this.formGroup.getRawValue().mfdType !== null) {
this.formGroup.controls.mfdType.setValue(null);
}
this.updateUsageUrl();
}
updateState(state: Partial<AppState>): void {
const updatedState = {
...this.state(),
...state,
};
if (!deepEqual(updatedState, this.state())) {
this.state.set({
...this.state(),
...state,
});
}
}
private addRequiredValidator(control: AbstractControl): void {
control.addValidators(control => Validators.required(control));
}
private createServiceEndpoint(
serviceUrl: string,
values: ControlForm,
): string {
const {sourceTree} = values;
return `${serviceUrl}/${sourceTree}`;
}
/**
* Return the matching setting group from a {@link MfdSource#tectonicSettings}.
*
* @param trees The settings groups
* @param source The MFD source
*/
private findSettingsGroup(
trees: SettingGroup[],
source: MfdSource,
): SettingGroup {
return trees.find(tree => tree.setting === source.tectonicSettings);
}
/**
* Return the matching setting group from a {@link MfdSource#tectonicSettings}
* and {@link MfdSource#sourceType}.
*
* @param trees The setting groups
* @param source The MFD source
*/
private findSourceGroup(
trees: SettingGroup[],
source: MfdSource,
): SourceGroup {
const settingsGroup = this.findSettingsGroup(trees, source);
return settingsGroup.data.find(data => data.type === source.sourceType);
}
private initialFormSet(): void {
this.formGroup.valueChanges.subscribe(() => this.updateUrl());
const defaultValues = this.defaultFormValues();
const queryParams = this.route.snapshot.queryParams as MfdQuery;
const model = queryParams.model ? queryParams.model : defaultValues.model;
const usage = this.state().usageResponses.get(model);
const defaultSource = this.defaultSource(usage.response.trees);
const defaultTreeInfo = this.defaultSourceTree(
usage.response.trees,
defaultSource,
);
const source: MfdSource =
queryParams.setting && queryParams.sourceType
? {
sourceType: queryParams.sourceType,
tectonicSettings: queryParams.setting,
}
: defaultSource;
const sourceTree = queryParams.sourceTree
? Number.parseInt(queryParams.sourceTree)
: null;
const formValues: ControlForm = {
cumulative: queryParams?.cumulative === 'true',
mfdType: defaultValues.mfdType,
model,
source,
sourceAsString: JSON.stringify(source),
sourceTree,
weightedMfds: queryParams?.weightedMfds === 'true',
};
this.formGroup.patchValue(formValues);
if (this.formGroup.valid) {
this.nshmpService.selectPlotControl();
this.callService();
} else if (this.formGroup.getRawValue() !== defaultValues) {
this.formGroup.markAsDirty();
}
if (formValues.sourceTree === null) {
this.formGroup.controls.sourceTree.setValue(defaultTreeInfo.id);
}
}
/**
* Add logic tree data by MFD branch.
*
* @param logicTreeData Logic tree data
* @param branch Source branch
* @param parent Logic tree parent
* @param type MFD type
*/
private logicTreeByMfdBranch(
logicTreeData: LogicTreeData,
branch: SourceBranch,
parent: string,
type: MfdType,
): void {
branch.mfds
.filter(mfdBranch => mfdBranch.mfd.props.type === type)
.forEach(mfdBranch => {
logicTreeData.labels.push(
`Branch: ${branch.branch}<br>` + `ID: ${mfdBranch.id}<br>`,
);
logicTreeData.parents.push(parent);
const props = Object.entries(mfdBranch.mfd.props)
.map(([key, value]: [string, string]) => `<br> ${key}: ${value}`)
.join('');
logicTreeData.text.push(
`Weight: ${mfdBranch.weight}<br><br>` + 'Properties:' + props,
);
});
}
/**
* Add logic tree data by type.
*
* @param logicTreeData Logic tree data
* @param branch Source branch
* @param parent Logic tree parent
*/
private logicTreeByType(
logicTreeData: LogicTreeData,
branch: SourceBranch,
parent: string,
): void {
const types = new Set(
branch.mfds.map(mfdBranch => mfdBranch.mfd.props.type),
);
types.forEach(type => {
const typeLabel = [`Branch: ${branch.branch} <br>`, `Type: ${type}`].join(
'',
);
logicTreeData.labels.push(typeLabel);
logicTreeData.parents.push(parent);
logicTreeData.text.push('');
this.logicTreeByMfdBranch(logicTreeData, branch, typeLabel, type);
});
}
/**
* Create the logic tree data from service response.
*
* @param serviceResponse MFD service response
*/
private logicTreeData(
serviceResponse: SourceLogicTreesResponse,
): LogicTreeData {
const tree = serviceResponse.response;
const root = tree.name;
const logicTreeData: LogicTreeData = {
labels: [root],
parents: [''],
text: [''],
};
tree.branches.forEach(branch => {
const branchLabel = [
`Branch: ${branch.branch}<br>`,
`Path: ${branch.path}<br>`,
`Name: ${branch.name}<br>`,
`Weight: ${branch.weight}`,
].join('');
logicTreeData.labels.push(branchLabel);
logicTreeData.parents.push(root);
logicTreeData.text.push('');
this.logicTreeByType(logicTreeData, branch, branchLabel);
});
return logicTreeData;
}
/**
* Create the application plots from the MFD service response.
*
* @param state application state
*/
private responseToPlots(
state: AppState,
formGroup: FormGroupControls<ControlForm>,
): Map<string, NshmpPlot> {
if (state.serviceResponse === null || state.serviceResponse === undefined) {
return state.plots;
}
const plots = new Map<string, NshmpPlot>();
const logicTreePlot = state.plots.get(Plots.LOGIC_TREE);
const logicTreePlotData = this.setLogicTreePlotData(
state.serviceResponse,
logicTreePlot,
);
plots.set(Plots.LOGIC_TREE, {
...logicTreePlot,
plotData: logicTreePlotData,
});
const mfdPlot = state.plots.get(Plots.MFD);
const mfdPlotData = this.setMfdPlotData(
state.serviceResponse,
mfdPlot,
formGroup.getRawValue(),
);
plots.set(Plots.MFD, {
...mfdPlot,
plotData: mfdPlotData,
});
return plots;
}
/**
* Returns the logic tree plot data.
*
* @param serviceResponse The MFD service response
* @param settings The plot settings
*/
private setLogicTreePlotData(
serviceResponse: SourceLogicTreesResponse,
plot: NshmpPlot,
): PlotlyPlot {
const {labels, parents, text} = this.logicTreeData(serviceResponse);
const logicTreePlotData: Partial<PlotData> = {
labels,
parents,
text,
type: 'treemap',
};
return {
config: {...plot.plotData.config},
data: [logicTreePlotData],
id: 'logic-tree-plot',
layout: {...plot.plotData.layout},
mobileConfig: {...plot.plotData.mobileConfig},
mobileLayout: {...plot.plotData.mobileLayout},
};
}
/**
* Returns the MFD plot data.
*
* @param serviceResponse The MFD service response
* @param form Control form field values
* @param settings Plot settings
*/
private setMfdPlotData(
serviceResponse: SourceLogicTreesResponse,
plot: NshmpPlot,
form: ControlForm,
): PlotlyPlot {
const tree = serviceResponse.response;
const totalMfd = form.cumulative
? Sequences.toCumulative(tree.totalMfd)
: tree.totalMfd;
const totalMfdData: Partial<PlotData> = {
line: {
color: 'black',
},
mode: 'lines+markers',
name: 'Total MFD',
x: totalMfd.xs,
y: totalMfd.ys,
};
const data = tree.branches
.map(branch => {
return this.filterMfds(branch.mfds, form.mfdType).map(mfdInfo => {
const name = `${branch.path} - ${mfdInfo.id}`;
let xySequence = hazardUtils.cleanXySequence(mfdInfo.mfd.data);
if (form.cumulative) {
xySequence = Sequences.toCumulative(xySequence);
}
let plotData: Partial<PlotData> = {
name: name.length > 50 ? `${name.substring(0, 50)} ...` : name,
x: xySequence.xs,
y: form.weightedMfds
? xySequence.ys.map(y => y * branch.weight * mfdInfo.weight)
: xySequence.ys,
};
if (mfdInfo.mfd.props.type === MfdType.SINGLE) {
// points for SINGLE type
plotData = {
...plotData,
marker: {
symbol: 'square',
},
mode: 'markers',
};
} else {
// line plot for all other type (all based on GR)
plotData = {
...plotData,
mode: 'lines+markers',
};
}
return plotData;
});
})
.reduce((prev, curr) => [...prev, ...curr]);
const title = `Magnitude Frequency Distribution: ${serviceResponse.response.name}`;
plot.settingsForm.patchValue({
layout: {
title: {
text: title,
},
},
});
const layout = plotUtils.updatePlotLabels({
layout: plot.plotData.layout,
title,
xLabel: plot.settingsForm.value.layout.xaxis.title.text,
yLabel: plot.settingsForm.value.layout.yaxis.title.text,
});
const mobileLayout = plotUtils.updatePlotLabels({
layout: plot.plotData.mobileLayout,
title,
xLabel: plot.settingsForm.value.layout.xaxis.title.text,
yLabel: plot.settingsForm.value.layout.yaxis.title.text,
});
return {
config: {...plot.plotData.config},
data:
form.mfdType === MfdType.ALL || form.mfdType === MfdType.TOTAL
? [totalMfdData, ...data]
: data,
id: 'mfd-plot',
layout,
mobileConfig: {...plot.plotData.mobileConfig},
mobileLayout,
};
}
private updateUrl(): void {
const values = this.formGroup.getRawValue();
const source = values.source;
const queryParams: MfdQuery = {
cumulative: values.cumulative.toString(),
model: values.model,
setting: source.tectonicSettings ?? null,
sourceTree: values.sourceTree?.toString() ?? null,
sourceType: source.sourceType ?? null,
weightedMfds: values.weightedMfds.toString(),
};
this.location.replaceState(
apps().source.mfd.routerLink,
new HttpParams().appendAll({...queryParams}).toString(),
);
}
private updateUsageUrl() {
const nshmService = this.state().nshmServices.find(
nshm => nshm.model === this.formGroup.getRawValue().model,
);
this.updateState({
serviceCallInfo: {
...this.state().serviceCallInfo,
usage: [nshmService.url],
},
});
}
}