diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.category.data.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.category.data.js new file mode 100644 index 0000000000000000000000000000000000000000..26bceaa67307aa639ca43b4777eb1cf2b45d4909 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.category.data.js @@ -0,0 +1,148 @@ +import React,{ Component } from "react"; +import { Bar } from 'react-chartjs-2'; +import _ from 'lodash'; +import { DataTable } from 'primereact/datatable'; +import { Column } from 'primereact/column'; +import MathUtility from "../../../utils/math.utility"; + +/** + * Component to show data ingested per category in cycle(s). + */ +class CycleCategoryWiseData extends Component{ + + constructor(props){ + super(props); + this.state= { + reportData:[] + }; + } + + getBarData() { + let reportData = this.getReportData(false); + return { + labels: _.map(reportData, 'cycle'), + datasets:[ + + { label: 'Raw IF', + data:_.map(reportData, 'rawIF'), + backgroundColor: '#4472C4', + barThickness: 75, + }, + { label: 'Raw BF', + data:_.map(reportData, 'rawBF'), + backgroundColor: '#ED7D31', + barThickness: 75, + + }, + { label: 'Raw TBB', + data:_.map(reportData, 'rawTBB'), + backgroundColor: '#A5A5A5', + barThickness: 75, + }, + { label: 'Preproc IF', + data:_.map(reportData, 'preprocIF'), + backgroundColor: '#FFC000', + barThickness: 75, + }, + { label: 'Pulp BF', + data:_.map(reportData, 'pulpBF'), + backgroundColor: '#44a3ce', + barThickness: 75, + }, + { label: 'Dynspec BF', + data:_.map(reportData, 'dynspecBF'), + backgroundColor: '#4caf50', + barThickness: 75, + } + ] + }; + } + + getBarOptions() { + return { + indexAxis: 'x', + elements: { + bar: { + borderWidth: 0, + }, + }, + scales: { + x: { + stacked: true, + categoryPercentage: 1.0, + barPercentage: 1.0 + }, + y: { + stacked: true, + // max: 5000, + } + }, + responsive: true, + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + text: 'Ingested Data per Type', + } + } + }; + } + + getReportData(isTableData) { + let reportData = []; + this.props.data.map(repData => { + let categoryData = {} + const cycleData = repData.data_ingested_per_site_and_category; + categoryData['cycle'] = repData.cycle; + // TODO: Update field names and values once API is complete + categoryData['rawIF'] = cycleData["Interferometric Observation"].dataproducts.length; + categoryData['rawBF'] = cycleData["Beamformed Observation"].dataproducts.length; + categoryData['rawTBB'] = cycleData.rawTBB; + categoryData['preprocIF'] = cycleData["Preprocessing Pipeline"].dataproducts.length; + categoryData['pulpBF'] = cycleData["Pulsar Pipeline"].dataproducts.length; + categoryData['dynspecBF'] = cycleData.dynspecBF; + reportData.push(categoryData); + }); + + if (isTableData) { + reportData.push({cycle: 'Average', + rawIF: MathUtility.getAverage(_.map(reportData, 'rawIF')), + rawBF: MathUtility.getAverage(_.map(reportData, 'rawBF')), + rawTBB: MathUtility.getAverage(_.map(reportData, 'rawTBB')), + preprocIF: MathUtility.getAverage(_.map(reportData, 'preprocIF')), + pulpBF: MathUtility.getAverage(_.map(reportData, 'pulpBF')), + dynspecBF: MathUtility.getAverage(_.map(reportData, 'dynspecBF')) + }); + } + return reportData; + } + + render() { + return( + <React.Fragment> + <div id={`cycles-telescope-time`} + style={{paddingTop: "10px", paddingBottom: "10px"}}> + <Bar data={this.getBarData()} options={this.getBarOptions()} width="50%" height="20" /> + </div> + + <div className="ttd-details" id={`cycle-ttd-details`}> + <DataTable value={this.getReportData(true)} resizableColumns columnResizeMode="expand" className="card" style={{paddingLeft: '0em', textAlign: 'center'}}> + <Column field="cycle" header="Cycle Code"></Column> + <Column field="rawIF" header="Raw IF"></Column> + <Column field="rawBF" header="Raw BF"></Column> + <Column field="rawTBB" header="Raw TBB"></Column> + <Column field="preprocIF" header="Preproc IF"></Column> + <Column field="pulpBF" header="Pulp BF"></Column> + <Column field="dynspecBF" header="Dynspec BF"></Column> + </DataTable> + </div> + + </React.Fragment> + ) + } + +} + +export default CycleCategoryWiseData; \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.intro.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.intro.js index 46c31e03392508687a9e603f6e4f50cc244c64bd..c774f584463b2b9c300cfa9250fb221aa7a191d9 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.intro.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.intro.js @@ -87,9 +87,9 @@ class CycleReportIntro extends Component { <li><a href="#avg_efficiency" >The average efficiency</a> matched with the expected or targeted or bench-marked average efficiency value for the cycle</li> <li><a href="#completion_level" >The completion level</a>, which shows the fraction of successful observations performed per the total number of observations earmarked for the cycle in question</li> <li><a href="#category_observations" >Observation hours per category</a>, which shows per single cycle the observing time fraction of successful Prio-A telescope hours, successful Prio-B telescope hours, System unavailability, Failed, System idle</li> - <li><a href="#" >The weekly efficiency</a>, which shows per single cycle fractions of observing hours of successful observations per week</li> - <li><a href="#" >Ingested data overview per site and category</a>, which shows per single cycle fractions of data products ingested per site and type (i.e. raw, (pre-)processed, interferometric, beamformed, tbb)</li> - <li><a href="#" >Projects summary overview</a>, which shows a tabular overview of the telescope resources (successful(/failed) telescope hours, processing hours, storage space at the LTA site(s)) used by the projects in that cycle</li> + <li><a href="#weekly_efficiency" >The weekly efficiency</a>, which shows per single cycle fractions of observing hours of successful observations per week</li> + <li><a href="#site_ingest_data" >Ingested data overview per site and category</a>, which shows per single cycle fractions of data products ingested per site and type (i.e. raw, (pre-)processed, interferometric, beamformed, tbb)</li> + <li><a href="#projects_summary" >Projects summary overview</a>, which shows a tabular overview of the telescope resources (successful(/failed) telescope hours, processing hours, storage space at the LTA site(s)) used by the projects in that cycle</li> <li><a href="#" >The ILT vs stand alone mode usage</a>, which shows the amount of hours spent in ILT-mode observing (i.e. the telescope is using the full array), ILT-mode idle / test (i.e. the full array is available but not performing production observations), Local-mode (i.e. the telescope array consist of Dutch station), ILT-mode (in total), ILT_mode_Dutch_array_observing (i.e. the the full array is available but performing production observations requiring only Dutch stations)</li> <li><a href="#" >The rate of failures</a>, which shows the rate of failures as a function of time</li> </ul> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.main.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.main.js index 84a7e41827ab5345806a9ab29fb4ead925c67156..137126a4276d2db31356fb9f707db0ab20cddc6a 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.main.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.main.js @@ -19,6 +19,9 @@ import CycleReportAvgEfficiency from './report.avg.efficiency'; import CycleCompletionLevel from './report.cycle.completion'; import CycleCategoryObservations from './report.category.observations'; import CycleWeeklyEfficiency from './report.weekly.efficiency'; +import CycleSiteWiseData from './report.site.data'; +import CycleCategoryWiseData from './report.category.data'; +import CycleProjectSummary from './report.project.summary'; // Constants for SU details table column property name to be used for identifying the properties in the // report data and title for displaying in reports and while exporting them. @@ -350,6 +353,18 @@ class CycleReportMain extends Component { <label>Weekly Efficiency</label> <CycleWeeklyEfficiency data={this.getReportData(REPORT_VARIABLE_MAP["WeeklyEfficiency"])} /> </div> + <div id="site_ingest_data"> + <label>Ingested Data per Site</label> + <CycleSiteWiseData data={this.getReportData(REPORT_VARIABLE_MAP["DataIngestedPerSite"])} /> + </div> + <div id="category_ingest_data"> + <label>Ingested Data per Category</label> + <CycleCategoryWiseData data={this.getReportData(REPORT_VARIABLE_MAP["DataIngestedPerCategory"])} /> + </div> + <div id="projects_summary"> + <label>Projects Summary Overview</label> + <CycleProjectSummary data={this.getReportData(REPORT_VARIABLE_MAP["ProjectSummary"])} /> + </div> {/* { this.renderCycleReports()} */} </div> {/* Dummy reference div to scroll down before exporting to PDF so that diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.project.summary.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.project.summary.js new file mode 100644 index 0000000000000000000000000000000000000000..d44aecff75968cc648ae60a17020f301a3eb80e1 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.project.summary.js @@ -0,0 +1,65 @@ +import React,{ Component } from "react"; +import { Bar } from 'react-chartjs-2'; +import _ from 'lodash'; +import { DataTable } from 'primereact/datatable'; +import { Column } from 'primereact/column'; +import MathUtility from "../../../utils/math.utility"; +import UnitConverter from "../../../utils/unit.converter"; + +/** + * Component to show projects summary in cycle. + */ +class CycleProjectSummary extends Component{ + + constructor(props){ + super(props); + } + + /** + * Returns the projects summary of the cycle(s) formatted to display in summary table. + * @returns Array of Cycle Projects list + */ + getReportData() { + let reportData = []; + const timeConversionFactor = UnitConverter.resourceUnitMap["time"].conversionFactor; + const dataConversionFactor = UnitConverter.resourceUnitMap["bytes"].conversionFactor; + this.props.data.map(repData => { + const cycleProjects = repData.projects_summary; + for (const projData of cycleProjects) { + let projectData = {} + projectData['cycle'] = repData.cycle; + projectData['project'] = projData.project; + // TODO: Update field names and values once API is complete + projectData['durationObserved'] = (projData.durations.total/timeConversionFactor).toFixed(2); + projectData['durationProcessed'] = projData.durations.processed; + projectData['dataToSara'] = projData["Sara"]; + projectData['dataToJuelich'] = projData["Juelich"]; + projectData['dataTopoznan'] = projData["Poznan"]; + reportData.push(projectData); + } + }); + return reportData; + } + + render() { + return( + <React.Fragment> + <div> + <DataTable value={this.getReportData()} resizableColumns columnResizeMode="expand" className="card" style={{paddingLeft: '0em', textAlign: 'center'}}> + <Column field="cycle" header="Cycle Code"></Column> + <Column field="project" header="Cycle Code"></Column> + <Column field="durationObserved" header="Time Observed (hr)"></Column> + <Column field="duratioProcessed" header="Time Processed (hr)"></Column> + <Column field="sara" header="Ingested To Sara data size (TB)"></Column> + <Column field="juelich" header="Ingested To Juelich data size (TB)"></Column> + <Column field="poznan" header="Ingested To Poznan data size (TB)"></Column> + </DataTable> + </div> + + </React.Fragment> + ) + } + +} + +export default CycleProjectSummary; \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.site.data.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.site.data.js new file mode 100644 index 0000000000000000000000000000000000000000..afc793a661f2c4a0a902cc1a25779f33ecd5c3fb --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Report/cycle/report.site.data.js @@ -0,0 +1,124 @@ +import React,{ Component } from "react"; +import { Bar } from 'react-chartjs-2'; +import _ from 'lodash'; +import { DataTable } from 'primereact/datatable'; +import { Column } from 'primereact/column'; +import MathUtility from "../../../utils/math.utility"; + +/** + * Component to show data ingested per site in cycle(s). + */ +class CycleSiteWiseData extends Component{ + + constructor(props){ + super(props); + this.state= { + reportData:[] + }; + } + + getBarData() { + let reportData = this.getReportData(false); + return { + labels: _.map(reportData, 'cycle'), + datasets:[ + + { label: 'Poznan', + data:_.map(reportData, 'poznan'), + backgroundColor: '#4472C4', + barThickness: 75, + }, + { label: 'Juelich', + data:_.map(reportData, 'juelich'), + backgroundColor: '#ED7D31', + barThickness: 75, + + }, + { label: 'Sara', + data:_.map(reportData, 'sara'), + backgroundColor: '#A5A5A5', + barThickness: 75, + } + ] + }; + } + + getBarOptions() { + return { + indexAxis: 'x', + elements: { + bar: { + borderWidth: 0, + }, + }, + scales: { + x: { + stacked: true, + categoryPercentage: 1.0, + barPercentage: 1.0 + }, + y: { + stacked: true, + // max: 5000, + } + }, + responsive: true, + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + text: 'Ingested Data per Site', + } + } + }; + } + + getReportData(isTableData) { + let reportData = []; + this.props.data.map(repData => { + let siteData = {} + const cycleData = repData.data_ingested_per_site_and_category; + siteData['cycle'] = repData.cycle; + // TODO: Update field names and values once API is complete + siteData['poznan'] = cycleData["Poznan"]; + siteData['juelich'] = cycleData["Juelich"]; + siteData['sara'] = cycleData["Sara"]; + reportData.push(siteData); + }); + + // if (isTableData) { + // reportData.push({cycle: 'Average', + // poznan: MathUtility.getAverage(_.map(reportData, 'poznan')), + // juelich: MathUtility.getAverage(_.map(reportData, 'juelich')), + // sara: MathUtility.getAverage(_.map(reportData, 'sara')) + // }); + // } + return reportData; + } + + render() { + return( + <React.Fragment> + <div id={`cycles-telescope-time`} + style={{paddingTop: "10px", paddingBottom: "10px"}}> + <Bar data={this.getBarData()} options={this.getBarOptions()} width="50%" height="20" /> + </div> + + <div className="ttd-details" id={`cycle-ttd-details`}> + <DataTable value={this.getReportData(true)} resizableColumns columnResizeMode="expand" className="card" style={{paddingLeft: '0em', textAlign: 'center'}}> + <Column field="cycle" header="Cycle Code"></Column> + <Column field="sara" header="To Sara (TB)"></Column> + <Column field="juelich" header="To Juelich (TB)"></Column> + <Column field="poznan" header="To Poznan (TB)"></Column> + </DataTable> + </div> + + </React.Fragment> + ) + } + +} + +export default CycleSiteWiseData; \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/cycle.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/cycle.service.js index 1d4af07452abdd6bce580c3e43dcdf5a1fdcbea7..b6cff97c04429a42d52aeea9ef8a2ac8ed156308 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/cycle.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/cycle.service.js @@ -867,16 +867,16 @@ const CycleService = { }, "data_ingested_per_site_and_category": { "Interferometric Observation": { - "dataproducts": [] + "dataproducts": [1,2,3,4] }, "Beamformed Observation": { - "dataproducts": [] + "dataproducts": [2,3,4] }, "Preprocessing Pipeline": { - "dataproducts": [] + "dataproducts": [1,2,3,4,5,6,7] }, "Pulsar Pipeline": { - "dataproducts": [] + "dataproducts": [1,1,1,1] } }, "projects_summary": [],