Skip to content

Commit

Permalink
Merge pull request #359 from micronutrientsupport/andan-effectiveness
Browse files Browse the repository at this point in the history
Andan effectiveness
  • Loading branch information
bgsandan authored Jun 5, 2024
2 parents f541837 + 7168929 commit 5b25f5b
Show file tree
Hide file tree
Showing 21 changed files with 1,893 additions and 10 deletions.
1 change: 1 addition & 0 deletions .env.defaults
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
NODE_ENV=production
LOG_LEVEL=info
MOUNT_DIR=/
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ REDIS_HOST=

PARSE_APP_ID=
PARSE_APP_URL=

MOUNT_DIR=
80 changes: 80 additions & 0 deletions src/controllers/intervention.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ import {
InterventionList,
InterventionMonitoringInformation,
InterventionPremixCalculator,
InterventionProjectedHouseholds,
InterventionRecurringCosts,
InterventionStartupScaleupCosts,
InterventionSummaryCosts,
InterventionThresholds,
InterventionUpdateDelta,
InterventionVehicleStandard,
} from '../models';
Expand All @@ -43,10 +45,12 @@ import {
InterventionMonitoringInformationRepository,
InterventionPremixCalculatorRepository,
InterventionPremixCostRepository,
InterventionProjectedHouseholdsRepository,
InterventionRecurringCostsRepository,
InterventionRepository,
InterventionStartupScaleupCostsRepository,
InterventionSummaryCostsRepository,
InterventionThresholdsRepository,
InterventionVehicleStandardRepository,
} from '../repositories';
import {StandardJsonResponse} from './standardJsonResponse';
Expand Down Expand Up @@ -289,6 +293,10 @@ export class InterventionController {
public interventionPremixCostRepository: InterventionPremixCostRepository,
@repository(InterventionPremixCalculatorRepository)
public interventionPremixCalculatorRepository: InterventionPremixCalculatorRepository,
@repository(InterventionProjectedHouseholdsRepository)
public interventionProjectedHouseholdsRepository: InterventionProjectedHouseholdsRepository,
@repository(InterventionThresholdsRepository)
public interventionThresholdsRepository: InterventionThresholdsRepository,
@repository(FortificationLevelRepository)
public fortificationLevelRepository: FortificationLevelRepository,
@inject(RestBindings.Http.RESPONSE) private response: Response,
Expand Down Expand Up @@ -862,6 +870,66 @@ export class InterventionController {
);
}

@get('/interventions/{id}/projected-households', {
description: 'get projected household numbers for intervention nation',
summary: 'get projected households',
operationId: 'projected-households',
responses: new StandardOpenApiResponses('Array of Intebr instances')
.setDataType('array')
.setObjectSchema(getModelSchemaRef(InterventionProjectedHouseholds))
.toObject(),
})
async getProjectedHouseholds(
@param.path.number('id') id: number,
): Promise<StandardJsonResponse<Array<InterventionProjectedHouseholds>>> {
const intervention = await this.interventionRepository.findById(id);
const countryId = intervention.countryId;

const filter: Filter = {
where: {
countryId: countryId,
},
};

const projectedHouseholds =
await this.interventionProjectedHouseholdsRepository.find(filter);

return new StandardJsonResponse<Array<InterventionProjectedHouseholds>>(
`Intervention data returned.`,
projectedHouseholds,
'InterventionProjectedHouseholds',
);
}

@get('/interventions/{id}/intake-thresholds', {
description: 'get intervention specific values for adequacy thresholds',
summary: 'get adequacy thresholds',
operationId: 'intake-thresholds',
responses: new StandardOpenApiResponses('Array of Intebr instances')
.setDataType('array')
.setObjectSchema(getModelSchemaRef(InterventionThresholds))
.toObject(),
})
async getIntakeThresholds(
@param.path.number('id') id: number,
): Promise<StandardJsonResponse<Array<InterventionThresholds>>> {
const filter: Filter = {
where: {
interventionId: id,
},
};

const intakeThresholds = await this.interventionThresholdsRepository.find(
filter,
);

return new StandardJsonResponse<Array<InterventionThresholds>>(
`Intervention data returned.`,
intakeThresholds,
'InterventionThresholds',
);
}

@get('/interventions/{id}/recurring-costs', {
description: 'get recurring',
summary: 'get recurring',
Expand Down Expand Up @@ -1075,6 +1143,18 @@ export class InterventionController {
transaction: tx,
},
);
} else if (delta.type && delta.type === 'intervention-thresholds') {
interventionUpdateDelta = new InterventionThresholds(delta);
console.log(interventionUpdateDelta);
await this.interventionThresholdsRepository.updateAll(
interventionUpdateDelta,
{
interventionId: id,
},
{
transaction: tx,
},
);
} else {
interventionUpdateDelta = new InterventionData(delta);
await this.interventionDataRepository.updateAll(
Expand Down
179 changes: 179 additions & 0 deletions src/controllers/send-data-controller.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Uncomment these imports to begin using these cool features!

import {inject} from '@loopback/core';
import {Filter, repository} from '@loopback/repository';
import {get, getModelSchemaRef} from '@loopback/rest';
import {DataVersion} from '../models';
import {
FctListFoodCompositionRepository,
FoodGeneraRepository,
FooditemRepository,
HouseholdConsumptionRepository,
HouseholdDetailsRepository,
IntakeThresholdRepository,
MicronutrientDropdownRepository,
} from '../repositories';
import {OpencpuService} from '../services';
import {StandardJsonResponse} from './standardJsonResponse';
import {StandardOpenApiResponses} from './standardOpenApiResponses';

// import {inject} from '@loopback/core';

export class SendDataControllerController {
constructor(
@inject('services.OpencpuService')
protected opencpuService: OpencpuService,
@repository(MicronutrientDropdownRepository)
public micronutrientRepository: MicronutrientDropdownRepository,
@repository(FoodGeneraRepository)
public foodGeneraRepository: FoodGeneraRepository,
@repository(HouseholdDetailsRepository)
public householdDetailsRepository: HouseholdDetailsRepository,
@repository(HouseholdConsumptionRepository)
public householdConsumptionRepository: HouseholdConsumptionRepository,
@repository(FooditemRepository)
public fooditemRepository: FooditemRepository,
@repository(IntakeThresholdRepository)
public intakeThresholdRepository: IntakeThresholdRepository,
@repository(FctListFoodCompositionRepository)
public fctListFoodCompositionRepository: FctListFoodCompositionRepository,
) {}

@get('self/email', {
summary: 'Get metadata about API and data versions',
description: 'Get metadata about API and data versions',
tags: ['meta'],
responses: new StandardOpenApiResponses(
'Array of DataVersion model instances',
)
.setDataType('array')
.setObjectSchema(getModelSchemaRef(DataVersion))
.toObject(),
})
async find(): Promise<object> {
const surveyFilter: Filter = {
where: {
surveyId: 1,
},
//limit: 5000,
};

let start = Date.now();
const householdDetails = await this.householdDetailsRepository.find(
surveyFilter,
);
let duration = (Date.now() - start) / 1000;
console.log(
`${householdDetails.length} household details fetched (${duration}s)`,
);

start = Date.now();
// Reduce the array to distinct surveyIds
const distinctFctListIds = householdDetails.reduce((acc, obj) => {
// Add the surveyId to a Set to ensure uniqueness
acc.add(obj.fctListId);
return acc;
}, new Set());

// Convert the Set to an array
const distinctFctListIdsArray = [...distinctFctListIds].filter(
value => value !== null,
);
duration = (Date.now() - start) / 1000;
console.log(`${distinctFctListIdsArray} distinct fcts, (${duration}s)`);

/*
const foodItems = await this.fooditemRepository.find();
const fcts = foodItems.reduce((acc, curr) => {
if (curr.fctSourceId) {
if (!acc[curr.fctSourceId.toString()]) {
acc[curr.fctSourceId] = [];
}
acc[curr.fctSourceId].push(curr);
}
return acc;
}, {} as {[key: string]: Fooditem[]});
console.log(`${Object.keys(fcts).length} fct tables fetched`);
*/
start = Date.now();
const householdConsumption = await this.householdConsumptionRepository.find(
surveyFilter,
);
duration = (Date.now() - start) / 1000;
console.log(
`${householdConsumption.length} consumption records fetched, (${duration}s)`,
);

const fctListFilter: Filter = {
where: {
fctListId: {
inq: distinctFctListIdsArray, // Define your array of possible values here
},
},
};
//const fctSource = await this.fctSourceRepository.find(omitGeometryFilter);

// const micronutrients = await this.micronutrientRepository.find();
// const foodGenera = await this.foodGeneraRepository.find();

start = Date.now();
const intakeThresholds = await this.intakeThresholdRepository.find();
duration = (Date.now() - start) / 1000;
console.log(
`${intakeThresholds.length} intake thresholds fetched (${duration}s)`,
);

start = Date.now();
const nctList = await this.fctListFoodCompositionRepository.find(
fctListFilter,
);
duration = (Date.now() - start) / 1000;
console.log(`${nctList.length} nct records fetched (${duration}s)`);

console.log('---------------------------');
console.log('Sending data to OpenCPU');

start = Date.now();
const foo = await this.opencpuService
.baselineInadequacy(
householdDetails,
householdConsumption,
nctList,
intakeThresholds,
)
.catch(e => {
console.error(e);
});
duration = (Date.now() - start) / 1000;

console.log(
`${(foo as any).body.length} inadequacy results (${duration}s)`,
);

// start = Date.now();
// const bar = await this.opencpuService
// .baselineInadequacyCND(
// householdDetails,
// householdConsumption,
// nctList,
// intakeThresholds,
// )
// .catch(e => console.error(e));
// duration = (Date.now() - start) / 1000;

// console.log(
// `${(bar as any).body.length} inadequacy CND results (${duration}s)`,
// );

return new StandardJsonResponse<Array<{}>>(
`1 data email sent.`,
[
{
inad: (foo as any).body,
// , inadCND: (bar as any).body
},
],
'',
);
}
}
58 changes: 57 additions & 1 deletion src/datasources/opencpu.datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,61 @@ const config = {
],
},
},
{
template: {
method: 'POST',
url:
process.env.OCPU_URL +
'/ocpu/apps/' +
process.env.OCPU_EFFECTIVENESS_PACKAGE +
'/R/' +
process.env.OCPU_EFFECTIVENESS_FUNCTION +
'/json',
body: {
householdDetails: '{householdDetails:object}',
householdConsumption: '{householdConsumption:object}',
nctList: '{nctList:object}',
intakeThresholds: '{intakeThresholds:object}',
},
fullResponse: true,
},
functions: {
baselineInadequacy: [
'householdDetails',
'householdConsumption',
'nctList',
'intakeThresholds',
],
},
},
{
template: {
method: 'POST',
url:
process.env.OCPU_URL +
'/ocpu/apps/' +
process.env.OCPU_EFFECTIVENESS_PACKAGE +
'/R/' +
process.env.OCPU_EFFECTIVENESS_FUNCTION +
'CND' +
'/json',
body: {
householdDetails: '{householdDetails:object}',
householdConsumption: '{householdConsumption:object}',
nctList: '{nctList:object}',
intakeThresholds: '{intakeThresholds:object}',
},
fullResponse: true,
},
functions: {
baselineInadequacyCND: [
'householdDetails',
'householdConsumption',
'nctList',
'intakeThresholds',
],
},
},
],
crud: false,
};
Expand All @@ -53,7 +108,8 @@ const config = {
@lifeCycleObserver('datasource')
export class OpencpuDataSource
extends juggler.DataSource
implements LifeCycleObserver {
implements LifeCycleObserver
{
static dataSourceName = 'opencpu';
static readonly defaultConfig = config;

Expand Down
Loading

0 comments on commit 5b25f5b

Please sign in to comment.