File

services/app.service.ts

Description

Entrypoint to store for disaggregation application.

Extends

SharedService

Index

Properties
Methods
Accessors

Constructor

constructor(formBuilder: FormBuilder, spinnerService: SpinnerService, nshmpService: NshmpService, hazardService: HazardService, route: ActivatedRoute, http: HttpClient, location: LocationService, localId: string)
Parameters :
Name Type Optional
formBuilder FormBuilder No
spinnerService SpinnerService No
nshmpService NshmpService No
hazardService HazardService No
route ActivatedRoute No
http HttpClient No
location LocationService No
localId string No

Methods

Private addRequiredValidator
addRequiredValidator(control: AbstractControl)
Parameters :
Name Type Optional
control AbstractControl No
Returns : void
addValidators
addValidators()
Returns : void
Private callFaultsService
callFaultsService()
Returns : void
Private callFeaturesUsage$
callFeaturesUsage$()

Check if FAULT is available.

Returns : Observable<void>
callService
callService()
Returns : void
Private componentDataToCSV
componentDataToCSV(componentData: DisaggComponentData, formValues: DisaggControlForm, showMetadata)

Convert disaggregation component data to CSV.

Parameters :
Name Type Optional Default value Description
componentData DisaggComponentData No

Disaggregation component data

formValues DisaggControlForm No

Form values

showMetadata No true
Returns : string
Private contributorsToCSV
contributorsToCSV(sources: DisaggSource[], formValues: DisaggControlForm, showMetadata)

Convert disaggregation contributions to CSV.

Parameters :
Name Type Optional Default value Description
sources DisaggSource[] No

Disaggregation sources

formValues DisaggControlForm No

Form values

showMetadata No true
Returns : string
defaultFormValues
defaultFormValues()

Returns the default form values.

Returns : DisaggControlForm
init
init()

Initialize applicaiton.

Returns : void
Private initialFormSet
initialFormSet()
Returns : void
initialState
initialState()

Disagg app initial state

Returns : AppState
Private maxDirectionSupported
maxDirectionSupported(state: DisaggControlForm)

Determines whether the current form state allows for max-direction scaling.

has a max-direction factor

Parameters :
Name Type Optional Description
state DisaggControlForm No

the form state

Returns : boolean

true if the selected disagg target is IML and the selected IMT has a max-direction factor

Private metadataCSV
metadataCSV(formValues: DisaggControlForm)

Returns the metadata in CSV.

Parameters :
Name Type Optional Description
formValues DisaggControlForm No

Form values

Returns : string
Private metadataText
metadataText(formValues: DisaggControlForm)
Parameters :
Name Type Optional
formValues DisaggControlForm No
Returns : string
onDisaggTarget
onDisaggTarget()
Returns : void
resetControlPanel
resetControlPanel()

Reset the control panel.

Returns : void
resetState
resetState()
Returns : void
saveComponentData
saveComponentData()

Save the component data.

Returns : void
saveComponentSummaryReport
saveComponentSummaryReport()
Returns : void
saveContributions
saveContributions(data: DisaggComponentData, formValues: DisaggControlForm)

Save the contributions.

Parameters :
Name Type Optional Description
data DisaggComponentData No

The component data

formValues DisaggControlForm No

The form values

Returns : void
saveSummary
saveSummary(data: DisaggComponentData, formValues: DisaggControlForm)

Save the summary.

Parameters :
Name Type Optional Description
data DisaggComponentData No

The component data

formValues DisaggControlForm No

The form values

Returns : void
saveSummaryReport
saveSummaryReport()
Returns : void
Private serviceEndpoint
serviceEndpoint(serviceUrl: string, values: DisaggControlForm)

Build the URL to call the appropriate backend service with the given values.

(should not have a trailing slash)

Parameters :
Name Type Optional Description
serviceUrl string No

the base to add the rest of the endpoint to (should not have a trailing slash)

values DisaggControlForm No

the values of the form

Returns : string

the service call URL

setLocation
setLocation(location: Location)

Set the location form fields.

Parameters :
Name Type Optional Description
location Location No

The location

Returns : void
Private summaryReportText
summaryReportText(componentData: DisaggComponentData, showMetadata)
Parameters :
Name Type Optional Default value
componentData DisaggComponentData No
showMetadata No true
Returns : string
Private summaryToText
summaryToText(summaries: DisaggSummary[], formValues: DisaggControlForm, showMetadata)

Convert the disaggregation summaries to text.

Parameters :
Name Type Optional Default value Description
summaries DisaggSummary[] No

The disaggregation summaries

formValues DisaggControlForm No

Form values

showMetadata No true
Returns : string
updateComponentData
updateComponentData()
Returns : void
Private updateDisaggData
updateDisaggData()
Returns : void
updateState
updateState(state: Partial<AppState>)
Parameters :
Name Type Optional
state Partial<AppState> No
Returns : void
Private updateUrl
updateUrl()
Returns : void
Private updateUsageUrl
updateUsageUrl()
Returns : void

Properties

Private endpoint
Default value : this.nshmpHazWs.services.curveServices.disagg

Disaggregation endpoint

Private featuresEndpoint
Default value : this.nshmpHazWs.services.curveServices.features

Features endpoint

Readonly formGroup
Default value : this.formBuilder.group<DisaggControlForm>( this.defaultFormValues(), )
Private nshmpHazWs
Default value : environment.webServices.nshmpHazWs

nshmp-haz-ws web config

Readonly state
Default value : signal<AppState>(this.initialState())

Accessors

availableModels
getavailableModels()

Returns the available models.

Returns : Signal<Parameter[]>
componentData
getcomponentData()

Returns the disagg response values observable.

Returns : Signal<DisaggComponentData>
disaggData
getdisaggData()

Returns the disaggregation data observable.

Returns : Signal<DisaggResponseDataValues>
faults
getfaults()
nshmService
getnshmService()

Returns the metadata of the NSHM observable.

Returns : Signal<NshmMetadata>
responseMetadata
getresponseMetadata()

Returns the response metadata observable.

Returns : Signal<DisaggResponseMetadata>
serviceCallInfo
getserviceCallInfo()

Returns the service call info.

Returns : Signal<ServiceCallInfo>
serviceResponse
getserviceResponse()

Returns the disagg response.

Returns : Signal<DisaggResponse>
usage
getusage()

Return the disagg usage.

Returns : Signal<DisaggUsage>
import {Location as LocationService} from '@angular/common';
import {HttpClient, HttpParams} from '@angular/common/http';
import {
  computed,
  Inject,
  Injectable,
  LOCALE_ID,
  Signal,
  signal,
} from '@angular/core';
import {AbstractControl, FormBuilder, Validators} from '@angular/forms';
import {ActivatedRoute} from '@angular/router';
import {
  DisaggControlForm,
  DisaggTarget,
  FormatLatitudePipe,
  FormatLongitudePipe,
  HazardService,
  hazardUtils,
  ReturnPeriodPipe,
} from '@ghsc/nshmp-lib-ng/hazard';
import {
  NshmpService,
  nshmpUtils,
  RETURN_PERIOD_BOUNDS,
  ReturnPeriod,
  ServiceCallInfo,
  SpinnerService,
} from '@ghsc/nshmp-lib-ng/nshmp';
import {
  DisaggComponentData,
  DisaggRequestMetadata,
  DisaggResponse,
  DisaggResponseDataValues,
  DisaggResponseMetadata,
  DisaggSource,
  DisaggSummary,
  DisaggUsage,
} from '@ghsc/nshmp-utils-ts/libs/nshmp-haz/www/disagg-service';
import {
  FeaturesUsageResponse,
  FeatureType,
} from '@ghsc/nshmp-utils-ts/libs/nshmp-haz/www/features-service';
import {NshmMetadata} from '@ghsc/nshmp-utils-ts/libs/nshmp-haz/www/nshm-service';
import {Location} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/geo';
import {Imt} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/gmm';
import {NshmId} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/nshm';
import {Parameter} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils/metadata';
import deepEqual from 'deep-equal';
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, forkJoin, map, Observable} from 'rxjs';

import {DisaggQuery} from '../models/disagg-query.model';
import {AppState} from '../models/state.model';

/**
 * Entrypoint to store for disaggregation application.
 */
@Injectable({
  providedIn: 'root',
})
export class AppService
  extends SharedService
  implements AppServiceModel<AppState, DisaggControlForm>
{
  /** nshmp-haz-ws web config */
  private nshmpHazWs = environment.webServices.nshmpHazWs;
  /** Disaggregation endpoint */
  private endpoint = this.nshmpHazWs.services.curveServices.disagg;
  /** Features endpoint */
  private featuresEndpoint = this.nshmpHazWs.services.curveServices.features;

  readonly formGroup = this.formBuilder.group<DisaggControlForm>(
    this.defaultFormValues(),
  );
  readonly state = signal<AppState>(this.initialState());

  constructor(
    private formBuilder: FormBuilder,
    private spinnerService: SpinnerService,
    private nshmpService: NshmpService,
    private hazardService: HazardService,
    private route: ActivatedRoute,
    private http: HttpClient,
    private location: LocationService,
    @Inject(LOCALE_ID) private localId: string,
  ) {
    super();
    this.addValidators();
    this.formGroup.controls.disaggComponent.disable();

    this.formGroup.controls.disaggComponent.valueChanges.subscribe(() =>
      this.updateComponentData(),
    );
  }

  /**
   * Returns the available models.
   */
  get availableModels(): Signal<Parameter[]> {
    return computed(() => this.state().availableModels);
  }

  /**
   * Returns the disagg response values observable.
   */
  get componentData(): Signal<DisaggComponentData> {
    return computed(() => this.state().componentData);
  }

  /**
   * Returns the disaggregation data observable.
   */
  get disaggData(): Signal<DisaggResponseDataValues> {
    return computed(() => this.state().disaggData);
  }

  get faults(): Signal<GeoJSON.FeatureCollection> {
    return computed(() => this.state().faults);
  }

  /**
   * Returns the metadata of the NSHM observable.
   */
  get nshmService(): Signal<NshmMetadata> {
    return computed(() =>
      this.state().nshmServices.find(
        nshmService => nshmService.model === this.formGroup.getRawValue().model,
      ),
    );
  }

  /**
   * Returns the response metadata observable.
   */
  get responseMetadata(): Signal<DisaggResponseMetadata> {
    return computed(() => this.state().serviceResponse?.response.metadata);
  }

  /**
   * Returns the service call info.
   */
  get serviceCallInfo(): Signal<ServiceCallInfo> {
    return computed(() => this.state().serviceCallInfo);
  }

  /**
   * Returns the disagg response.
   */
  get serviceResponse(): Signal<DisaggResponse> {
    return computed(() => this.state().serviceResponse);
  }

  /**
   * Return the disagg usage.
   */
  get usage(): Signal<DisaggUsage> {
    return computed(() =>
      this.state().usageResponses?.get(this.formGroup.getRawValue().model),
    );
  }

  addValidators(): void {
    const controls = this.formGroup.controls;

    this.addRequiredValidator(controls.imt);
    this.addRequiredValidator(controls.latitude);
    this.addRequiredValidator(controls.longitude);
    this.addRequiredValidator(controls.model);
    this.addRequiredValidator(controls.siteClass);
    this.addRequiredValidator(controls.vs30);

    controls.iml.addValidators([
      control => {
        if (this.formGroup.getRawValue().disaggTarget === DisaggTarget.IML) {
          return Validators.required(control);
        } else {
          return Validators.nullValidator(control);
        }
      },
    ]);

    controls.returnPeriod.addValidators([
      control => {
        if (
          this.formGroup.getRawValue().disaggTarget ===
          DisaggTarget.RETURN_PERIOD
        ) {
          return Validators.required(control);
        } else {
          return Validators.nullValidator(control);
        }
      },
      Validators.min(RETURN_PERIOD_BOUNDS.min),
      Validators.max(RETURN_PERIOD_BOUNDS.max),
    ]);

    controls.latitude.addValidators(this.validateNan());
    controls.longitude.addValidators(this.validateNan());

    this.formGroup.updateValueAndValidity();
  }

  callService(): void {
    const spinnerRef = this.spinnerService.show(
      `${SpinnerService.MESSAGE_SERVICE}
      <br>
      (Could take 30+ seconds)
      `,
    );
    const values = this.formGroup.getRawValue();

    const service = this.nshmService();
    const serviceUrl = `${service.url}${this.endpoint}`;
    const url = this.serviceEndpoint(serviceUrl, values);

    forkJoin([
      this.nshmpService.callService$<DisaggResponse>(url),
      this.callFeaturesUsage$(),
    ])
      .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.updateComponentData();
        this.updateDisaggData();

        this.formGroup.controls.disaggComponent.enable();
      });
  }

  /**
   * Returns the default form values.
   */
  defaultFormValues(): DisaggControlForm {
    return {
      ...hazardUtils.hazardDefaultFormValues(),
      commonReturnPeriods: ReturnPeriod.RP_2475,
      disaggComponent: 'Total',
      disaggTarget: DisaggTarget.RETURN_PERIOD,
      iml: null,
      imt: Imt.PGA,
      maxDirection: false,
      vs30: 760,
    };
  }

  /**
   * Initialize applicaiton.
   */
  init(): void {
    const spinnerRef = this.spinnerService.show(
      SpinnerService.MESSAGE_METADATA,
    );
    const service = environment.webServices.nshmpHazWs;
    const endpoint = service.services.curveServices.disagg;

    this.hazardService
      .dynamicNshms$<DisaggRequestMetadata>(
        `${service.url}${service.services.nshms}`,
        endpoint,
      )
      .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();
      });
  }

  /**
   * Disagg app initial state
   */
  initialState(): AppState {
    const usageResponses: Map<string, DisaggUsage> = new Map();
    usageResponses.set(NshmId.CONUS_2018, null);

    return {
      availableModels: [],
      componentData: null,
      disaggData: null,
      faults: null,
      nshmServices: [],
      plots: null,
      responseSpectra: null,
      serviceCallInfo: {
        serviceCalls: [],
        serviceName: 'Disaggregation',
        usage: [],
      },
      serviceResponse: null,
      usageResponses,
    };
  }

  onDisaggTarget(): void {
    if (this.formGroup.getRawValue().disaggTarget === DisaggTarget.IML) {
      this.formGroup.controls.returnPeriod.disable();
      this.formGroup.controls.commonReturnPeriods.disable();
      this.formGroup.controls.iml.enable();
      this.formGroup.controls.maxDirection.enable();
    } else {
      this.formGroup.controls.returnPeriod.enable();
      this.formGroup.controls.commonReturnPeriods.enable();
      this.formGroup.controls.iml.disable();
      this.formGroup.controls.maxDirection.disable();
    }
  }

  /**
   * Reset the control panel.
   */
  resetControlPanel(): void {
    this.formGroup.reset(this.defaultFormValues());
    this.resetState();
  }

  resetState(): void {
    this.updateState({
      faults: null,
      plots: this.initialState().plots,
      serviceCallInfo: {
        ...this.state().serviceCallInfo,
        serviceCalls: [],
      },
      serviceResponse: null,
    });
    this.formGroup.controls.disaggComponent.disable();
    this.updateUsageUrl();
  }

  /**
   * Save the component data.
   */
  saveComponentData(): void {
    const data = this.componentData();

    const blob = new Blob(
      [this.componentDataToCSV(data, this.formGroup.getRawValue())],
      {
        type: 'text/csv;charset=utf-8;',
      },
    );

    this.nshmpService.saveAs(blob, `disagg-${data.component}.csv`);
  }

  saveComponentSummaryReport(): void {
    const blob = new Blob([this.summaryReportText(this.componentData())], {
      type: 'text/csv;charset=utf-8;',
    });

    this.nshmpService.saveAs(
      blob,
      `disagg-summary-${this.componentData().component}.txt`,
    );
  }

  /**
   * Save the contributions.
   *
   * @param data The component data
   * @param formValues The form values
   */
  saveContributions(
    data: DisaggComponentData,
    formValues: DisaggControlForm,
  ): void {
    const blob = new Blob([this.contributorsToCSV(data.sources, formValues)], {
      type: 'text/csv;charset=utf-8;',
    });
    this.nshmpService.saveAs(blob, `disagg-sources-${data.component}.csv`);
  }

  /**
   * Save the summary.
   *
   * @param data The component data
   * @param formValues The form values
   */
  saveSummary(data: DisaggComponentData, formValues: DisaggControlForm): void {
    const blob = new Blob([this.summaryToText(data.summary, formValues)], {
      type: 'text/csv;charset=utf-8;',
    });
    this.nshmpService.saveAs(blob, `disagg-summary-${data.component}.txt`);
  }

  saveSummaryReport(): void {
    const summaries = this.disaggData().data.map((data, index) =>
      this.summaryReportText(data, index === 0),
    );

    const blob = new Blob(summaries, {
      type: 'text/csv;charset=utf-8',
    });

    this.nshmpService.saveAs(blob, 'dissag-summary.txt');
  }

  /**
   * Set the location form fields.
   *
   * @param location The location
   */
  setLocation(location: Location): void {
    this.formGroup.patchValue({
      latitude: location.latitude,
      longitude: location.longitude,
    });
  }

  updateComponentData(): void {
    this.updateDisaggData();

    const componentData = this.disaggData()?.data.find(
      disagg =>
        disagg.component === this.formGroup.getRawValue().disaggComponent,
    );

    this.updateState({
      componentData,
    });
  }

  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 callFaultsService(): void {
    const url = `${this.nshmService().url}${this.featuresEndpoint}/${FeatureType.FAULT}/true`;

    this.http.get<GeoJSON.FeatureCollection>(url).subscribe(faults => {
      this.updateState({
        faults,
      });
    });
  }

  /**
   * Check if FAULT is available.
   */
  private callFeaturesUsage$(): Observable<void> {
    const url = `${this.nshmService().url}${this.featuresEndpoint}`;

    return this.http.get<FeaturesUsageResponse>(url).pipe(
      map(featureUsage => {
        const featureTypes = featureUsage.response.featureType.map(
          feature => feature.value,
        );

        if (featureTypes.includes(FeatureType.FAULT)) {
          this.callFaultsService();
        }
      }),
    );
  }

  /**
   * Convert disaggregation component data to CSV.
   *
   * @param componentData Disaggregation component data
   * @param formValues Form values
   */
  private componentDataToCSV(
    componentData: DisaggComponentData,
    formValues: DisaggControlForm,
    showMetadata = true,
  ): string {
    const metadata = this.serviceResponse().response.metadata;
    const bins = metadata.εbins;
    const keys = componentData.summary.find(
      data => data.name.toLowerCase() === 'epsilon keys',
    );

    const headers = [
      'Distance (km)',
      'Magnitude (Mw)',
      'ε total',
      ...keys.data.map(data => data.name),
    ];

    const csv = componentData.data.map(data => {
      const εvalues = bins.map(
        bin => data.εdata.find(data => data.εbin === bin.id)?.value ?? 0.0,
      );
      const sum = εvalues.reduce((a, b) => a + b, 0);
      const values = [sum, ...εvalues]
        .map(num => num.toExponential(3))
        .join(', ');

      return `${data.r}, ${data.m}, ${values}`;
    });

    const table = `${headers.join(', ')}\n${csv.join('\n')}`;

    return showMetadata
      ? `${this.metadataCSV(formValues)}\n\n\n` + table
      : table;
  }

  /**
   * Convert disaggregation contributions to CSV.
   *
   * @param sources Disaggregation sources
   * @param formValues Form values
   */
  private contributorsToCSV(
    sources: DisaggSource[],
    formValues: DisaggControlForm,
    showMetadata = true,
  ): string {
    const label = 'Disaggregation Contributions';

    if (sources === null || sources.length === 0) {
      return `${label}: N/A\n\n`;
    }
    const headers = 'Source Set ↳ Source, Type, r, m, ε0, lon, lat, az, %';

    const csv = sources
      .map(source => {
        const name =
          source.type === 'SINGLE' ? `\t\t${source.name}` : source.name;
        return (
          `"${name}", ${source.type}, ${source.r}, ${source.m}, ${source.ε}, ` +
          `${source.longitude}, ${source.latitude}, ${source.azimuth}, ${source.contribution}\n`
        );
      })
      .map(source => source.replace(/null/gi, ''))
      .join('');

    const table = `${label}\n${headers}\n ${csv}\n\n`;

    return showMetadata
      ? `${this.metadataCSV(formValues)}\n\n ${table}`
      : table;
  }

  private initialFormSet(): void {
    const query = this.route.snapshot.queryParams as DisaggQuery;
    const defaultValues = this.defaultFormValues();

    const formValues: DisaggControlForm = {
      commonReturnPeriods: defaultValues.commonReturnPeriods,
      disaggComponent: query.disaggComponent
        ? query.disaggComponent
        : defaultValues.disaggComponent,
      disaggTarget:
        DisaggTarget[query.disaggTarget] ?? defaultValues.disaggTarget,
      iml: query.iml ? Number.parseFloat(query.iml) : defaultValues.iml,
      imt: query.imt ? query.imt : defaultValues.imt,
      latitude: query.latitude
        ? Number.parseFloat(query.latitude)
        : defaultValues.latitude,
      longitude: query.longitude
        ? Number.parseFloat(query.longitude)
        : defaultValues.longitude,
      maxDirection: query.maxDirection
        ? query.maxDirection === 'true'
        : defaultValues.maxDirection,
      model: query.model ? query.model : defaultValues.model,
      returnPeriod: query.returnPeriod
        ? Number.parseInt(query.returnPeriod, 10)
        : defaultValues.returnPeriod,
      siteClass: query.siteClass ? query.siteClass : defaultValues.siteClass,
      vs30: query.vs30 ? Number.parseFloat(query.vs30) : defaultValues.vs30,
    };

    formValues.maxDirection &&= this.maxDirectionSupported(formValues);

    this.formGroup.patchValue(formValues);
    this.onDisaggTarget();

    if (this.formGroup.valid) {
      this.nshmpService.selectPlotControl();
      this.callService();
    } else if (this.formGroup.getRawValue() !== defaultValues) {
      this.formGroup.markAsDirty();
    }

    this.formGroup.valueChanges.subscribe(() => this.updateUrl());
  }

  /**
   * Determines whether the current form state allows for max-direction scaling.
   *
   * @param state the form state
   * @returns true if the selected disagg target is IML and the selected IMT
   *    has a max-direction factor
   */
  private maxDirectionSupported(state: DisaggControlForm): boolean {
    return (
      state.disaggTarget === DisaggTarget.IML &&
      state.imt in hazardUtils.MAX_DIRECTION
    );
  }

  /**
   * Returns the metadata in CSV.
   *
   * @param formValues Form values
   */
  private metadataCSV(formValues: DisaggControlForm): string {
    return (
      'Metadata\n' +
      'Model, Longitude, Latitude, IMT, Return Period, VS30\n' +
      `${formValues.model}, ${formValues.longitude}, ${formValues.latitude}, ` +
      `${formValues.imt}, ${formValues.returnPeriod}, ${formValues.vs30}`
    );
  }

  private metadataText(formValues: DisaggControlForm): string {
    const usage = this.usage().response;

    const imt = usage.model.imts.find(
      imt => imt.value === formValues.imt.toString(),
    )?.display;

    const vs30 =
      formValues.siteClass === nshmpUtils.selectPlaceHolder().value
        ? `${formValues.vs30} m/s`
        : `${formValues.vs30} m/s (${formValues.siteClass})`;

    return (
      `Model: ${usage.model.name}\n` +
      `Longitude: ${new FormatLongitudePipe(this.localId).transform(formValues.longitude)} \n` +
      `Latitude: ${new FormatLatitudePipe(this.localId).transform(formValues.latitude)} \n` +
      `IMT: ${imt} \n` +
      `Return Period: ${new ReturnPeriodPipe().transform(formValues.returnPeriod)} \n` +
      `VS30: ${vs30} \n\n`
    );
  }

  /**
   * Build the URL to call the appropriate backend service with the given values.
   *
   * @param serviceUrl the base to add the rest of the endpoint to
   * (should not have a trailing slash)
   * @param values the values of the form
   * @returns the service call URL
   */
  private serviceEndpoint(
    serviceUrl: string,
    values: DisaggControlForm,
  ): string {
    const pathBase = `${serviceUrl}/${values.longitude}/${values.latitude}/${values.vs30}`;
    const queryBase = '?out=DISAGG_DATA,GMM,SOURCE';
    const {disaggTarget} = values;

    switch (disaggTarget) {
      case DisaggTarget.IML: {
        const iml =
          values.maxDirection && values.imt in hazardUtils.MAX_DIRECTION
            ? values.iml / hazardUtils.MAX_DIRECTION[values.imt]
            : values.iml;
        return `${pathBase}${queryBase}&${values.imt}=${iml}`;
      }
      case DisaggTarget.RETURN_PERIOD: {
        return `${pathBase}/${values.returnPeriod}${queryBase}&imt=${values.imt}`;
      }
      default:
        throw new Error(`Disagg target [${values.disaggTarget}] not supported`);
    }
  }

  private summaryReportText(
    componentData: DisaggComponentData,
    showMetadata = true,
  ): string {
    const formValues = this.formGroup.getRawValue();
    const firstLine = '*** Disaggregation of Seismic Hazard ***';
    const metadata = showMetadata
      ? `${firstLine}\n\n${this.metadataText(formValues)}`
      : '';

    return (
      metadata +
      `** Disaggregation Component: ${componentData.component} **\n\n` +
      this.summaryToText(componentData.summary, formValues, false) +
      '\n\n' +
      this.componentDataToCSV(componentData, formValues, false) +
      '\n\n' +
      this.contributorsToCSV(componentData.sources, formValues, false)
    );
  }

  /**
   * Convert the disaggregation summaries to text.
   *
   * @param summaries The disaggregation summaries
   * @param formValues Form values
   */
  private summaryToText(
    summaries: DisaggSummary[],
    formValues: DisaggControlForm,
    showMetadata = true,
  ): string {
    const text = summaries.map(summary => {
      const name = summary.name;
      const values = summary.data.map(data => {
        const units = data.units === null ? '' : data.units;
        return `\t${data.name}: ${data.value}${units}`;
      });
      return `${name}:\n` + values.join('\n');
    });

    return showMetadata
      ? `${this.metadataCSV(formValues)}\n\n\n` + `${text.join('\n\n')}`
      : `${text.join('\n\n')}`;
  }

  private updateDisaggData(): void {
    const disaggData = this.state().serviceResponse?.response.disaggs.find(
      disagg =>
        disagg.imt.value === this.formGroup.getRawValue().imt.toString(),
    );

    this.updateState({
      disaggData,
    });
  }

  private updateUrl(): void {
    this.location.replaceState(
      apps().hazard.disagg.routerLink,
      new HttpParams().appendAll(this.formGroup.getRawValue()).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}${this.endpoint}`],
      },
    });
  }
}

results matching ""

    No results matching ""