### activity based
```ts
function calculateEmissionByActivity(activity: ActivityDTO) : {
calculatedAt: Date;
totalEmission: number;
materialEmission?: number;
transportationEmission?: number;
}
```
```ts
// Database `cccdb`
// Type: subcollection
// Collection name `activities`
// Schema version 1.0
interface calculatedEmissionSnapshot {
calculatedAt: Date;
totalEmission: number;
materialEmission?: number;
transportationEmission?: number;
}
export interface ActivityDTO {
uid: string;
emissionSource: string;
activityRemark?: string;
vcaNodeId?: string;
batchId?: string;
materialBased?: {
materialResourceType: string;
unitAmount: number;
unit: string;
};
// either
transportationDistanceBased?: {
transportVehicleResourceType: string;
transportWeight: number;
transportDistance: number;
transportDepartPercentage: number;
transportArrivePercentage: number;
};
// or
transportationFuelAmountBased?: {
transportFuelResourceType: string;
transportFuelUnitAmount: number;
transportFuelUnit: string;
};
allocation: {
allocationType: 'no_allocation' // default
| 'energy_based'
| 'physical_based'
| 'economic_based'
| 'other';
mainProduct?: number;
coProduct?: number;
allocationPercentage: number; // default = 100%
};
recycle: {
recycleType:
| 'no_recycle'
| 'primary_manual_input'
| 'secondary_tgo_material_based';
recycleMaterial?: 'rubber' | 'paper' | 'plastic';
recycleRate: number;
};
calculatedEmission?: calculatedEmissionSnapshot[];
createdAt: Date;
updatedAt: Date;
}
```
```ts
// Database `cccdb`
// Type: subcollection
// Collection name `emissionfactors`
// Collection name `emissionfactors` can be a standalone collection as a global emission factor library
// Or
// Under collection `businesses`, say, a business can have multiple emission factors
// Schema version 1.0
export interface GlobalWarmingPotentialDto {
uid: string;
commonName: string;
formulaName: string;
gwp100yr: number;
}
interface CustomEFValue {
gwpId: string;
value: number;
}
export interface EmissionFactorDto {
uid: string;
name: string;
source: 'self' | 'supplier' | 'TGO' | 'predefined';
type: 'co2_only' | 'multiple_ghgs';
value: number | CustomEFValue[];
unit: {
id: string;
name: string;
};
isSupportingProcess?: boolean;
date?: Date;
status?: 'active' | 'inactive';
stage: 'unverified' | 'verified' | 'verifing';
belongTo?: string; // in case of self, supplier, or predefined emission factors
createdAt: Date;
updatedAt: Date;
}
```
##### Unit Converter
(input unitAmount, input unit, resourceType) -> (desiredUnitAmount, desiredUnit)
1. convert to standard unit
1. `unit.toSI()`
2. if unit is not in the same category
1. cross-category conversion
1. if desired unit is weight and input unit is in volume
1. `desiredUnitAmount` = `unitAmount` x `resourceType.flexibilityOfUnit.density`
2. if desired unit is volume and input unit is in weight
1. `desiredUnitAmount` = `unitAmount` / `resourceType.flexibilityOfUnit.density`
3. if desired unit is power and input unit is in time
1. `desiredUnitAmount` = `unitAmount` x `resourceType.flexibilityOfUnit.powerConsumption`
3. `unit.to(desiredUnit)`
#### Flow
1. get `ActivityDTO` from parameter
2. set `is materialEmission` = 0, `transportationEmission` = 0
3. calculate material based emission
1. if `materialBased`
1. lookup `materialResourceType`
2. ef = `materialResourceType.ef`
3. if `ef.unit` !== `materialBased.unit`
1. unit converter
4. `materialEmission` = `convertedUnitAmount` * `ef.value`
2. else skip
4. calculate transportation based emission
1. if `transportationDistanceBased`
1. select depart, arrival ef from `transportVehicleResourceType`, `transportDepartPercentage`, `transportArrivePercentage` -> look for it in system config json
2. unit converter for `transportWeight`, `transportDistance`
3. calculate depart load
1. `transportWeight` x `transportDistance`
4. calculate arrival load
1. `depart load` / `maximumLoadTonne`
4.`transportationEmission` = `depart load` x `depart ef` + `arrival load` x `arrived ef`
2. else if `transportationFuelAmountBased`
1. lookup `transportFuelResourceType`
2. ef = `transportFuelResourceType.ef`
3. if `ef.unit` !== `transportFuelUnit`
1. unit converter
4. `transportationEmission` = `convertedUnitAmount` * `ef.value`
3. else skip
5. recycle
1. activity category = waste or eol
1. if `recycleType` === `no_recycle`
2. else if `recycleType` === `primary_manual_input`
1. `materialEmission` = `materialEmission` x `(1 - recycleRate)`
3. else if `recycleType` === `secondary_tgo_material_based`
1. if `recycleMaterial` === `rubber`
1. `recycleRate` = xx
2. else if `recycleMaterial` === `paper`
1. `recycleRate` = xx
3. else if `recycleMaterial` === `plastic`
1. `recycleRate` = xx
4. `materialEmission` = `materialEmission` x `(1 - recycleRate)`
6. allocation
1. if `allocationType` === `no_allocation` skip
2. else if `allocationType` === `energy_based` or `physical_based` or `economic_based`
1. `allocationPercentage` = `mainProduct` / (`mainProduct` + `coProduct`)
3. `materialEmission` = `materialEmission` x `allocationPercentage`
4. `transportationEmission` = `transportationEmission` x `allocationPercentage`
7. output
1. `timestamp`
2. `totalEmission = materialEmission` + `transportationEmission`
3. `materialEmission`
4. `transportationEmission`
transportation resourcetype config
```js
[
{
transportVehicleResourceType: "รถบรรทุก 6 ล้อ ขนส่งแบบปกติ",
maxmimumLoadTonne: 100,
efs: [
{
"loadPercentage": 100,
// อาจจะ ref ไปหาตัวที่เก็บในระบบ
"unitAmount": 2.34,
"unit": "km"
},
{
"loadPercentage": 75,
"unitAmount": 2.34,
"unit": "km"
}
...
]
}
...
]
```
```mermaid
graph TD
A[Start] --> B[Get ActivityDTO]
B --> C[Set materialEmission = 0, transportationEmission = 0]
subgraph "Unit Converter"
UC1[Input: unitAmount, unit, resourceType] --> UC2[Convert to standard unit]
UC2 --> UC3{Units in same category?}
UC3 -->|No| UC4{Cross-category conversion}
UC4 -->|Weight to Volume| UC5[Use density]
UC4 -->|Volume to Weight| UC6[Use inverse density]
UC4 -->|Time to Power| UC7[Use powerConsumption]
UC3 -->|Yes| UC8[Convert to desired unit]
UC5 --> UC8
UC6 --> UC8
UC7 --> UC8
UC8 --> UC9[Output: desiredUnitAmount, desiredUnit]
end
C --> D{Is materialBased?}
D -->|Yes| E[Lookup materialResourceType]
E --> F[ef = materialResourceType.ef]
F --> G{ef.unit != materialBased.unit?}
G -->|Yes| H[Unit Converter]
G -->|No| I[materialEmission = amount * ef.value]
H --> I
D -->|No| J[Skip material emission]
I --> J
J --> K{Transportation type?}
K -->|Distance based| L1[Lookup transportVehicleResourceType]
L1 --> L2[Get transportDepartPercentage]
L2 --> L3[Get transportArrivePercentage]
L3 --> L4[Get depart ef and arrive ef from system config]
L4 --> M1[Calculate depart load: transportWeight * transportDistance]
M1 --> N1[Get maximumLoadTonne from system config]
N1 --> N2[Calculate arrival load: depart load / maximumLoadTonne]
N2 --> O1[Calculate depart emission: depart load * depart ef]
O1 --> O2[Calculate arrive emission: arrival load * arrive ef]
O2 --> O3[transportationEmission = depart emission + arrive emission]
K -->|Fuel amount based| P[Lookup transportFuelResourceType]
P --> Q[ef = transportFuelResourceType.ef]
Q --> R{ef.unit != transportFuelUnit?}
R -->|Yes| S[Unit Converter]
R -->|No| T[transportationEmission = amount * ef.value]
S --> T
K -->|None| U[Skip transportation emission]
O3 --> U
T --> U
U --> V{Is activity waste or EOL?}
V -->|Yes| W{Recycle Type?}
W -->|No recycle| X[Skip recycle]
W -->|Primary manual input| Y[materialEmission *= 1 - recycleRate]
W -->|Secondary TGO material based| Z{Recycle Material?}
Z -->|Rubber| AA[Set recycleRate for rubber]
Z -->|Paper| AB[Set recycleRate for paper]
Z -->|Plastic| AC[Set recycleRate for plastic]
AA --> AD[materialEmission *= 1 - recycleRate]
AB --> AD
AC --> AD
V -->|No| AE[Skip recycle]
X --> AE
Y --> AE
AD --> AE
AE --> AF{Allocation Type?}
AF -->|No allocation| AG[Skip allocation]
AF -->|Energy/Physical/Economic based| AH[Calculate allocationPercentage]
AH --> AI[Apply allocation to emissions]
AG --> AJ[Prepare output]
AI --> AJ
AJ --> AK[Set timestamp]
AK --> AL[Calculate totalEmission]
AL --> AM[Output materialEmission]
AM --> AN[Output transportationEmission]
AN --> AO[End]
```
### batch based
```ts
function calculateEmissionByฺBatch(activity: BatchDTO) : {
calculatedAt: Date;
totalEmission: number;
materialEmission?: number;
transportationEmission?: number;
}
```
```ts
// Database `cccdb`
// Type: sub of subcollection
// Collection name `batches`
// Under collection `businesses` and sub collection `products` say, a product can have multiple batches
// Schema version 1.0
// Define BatchDto interface
export interface BatchDto {
// Unique identifier
uid: string;
// Batch data
name?: string;
startDate?: Date;
endDate?: Date;
durationInDays?: number;
status: 'active' | 'inactive' | 'deleted';
stage: 'created' | 'on_progress' | 'finalized';
// Update
activities: ActivityDTO[];
// Metadata
createdBy: string;
createdAt: Date;
updatedBy?: string;
updatedAt: Date;
}
```
### Flow
input:
(batch ID, Output JSON Structure)
1. query data and aggregate into groups
1. User request activities corresponding with Batch ID
2. Lookup for batch with batch ID
3. `activities` = `batch.activities`
4. group `activities` by `chainId`
1. for each group, group by `vcaNodeId`
2. emission Calculation
1. activities Level:
1. use `Activity Based Calculator`
2. subStages Level (Node)
1. sum every activities
2. output { `totalSubstageEmissions`, `totalSubstageMaterialBasedEmissions`, `totalSubstageTransportationBasedEmissions`}
3. stages Level:
1. sum every substages emission
2. output {`totalStageEmissions`, `totalStageMaterialBasedEmissions`, `totalStageTransportationBasedEmissions`}
4. batch level
1. sum every stages emission
2. output {`timestamp`, `totalBatchEmissions`, `totalBatchMaterialBasedEmissions`, `totalBatchTransportationBasedEmissions`}
```mermaid
graph TD
A[Start] --> B[Input: Batch ID, Output JSON Structure]
subgraph "1. Query Data and Aggregate"
B --> C[Query activities for Batch ID]
C --> D[Lookup batch with batch ID]
D --> E[activities = batch.activities]
E --> F[Group activities by chainId]
F --> G[For each chainId group, group by vcaNodeId]
end
subgraph "2. Emission Calculation"
G --> H[Activities Level Calculation]
H --> I[Use Activity Based Calculator]
I --> J[Substages Level Calculation]
J --> K[Sum emissions for all activities in substage]
K --> L[Output substage emissions]
L --> L1["{ totalSubstageEmissions,
totalSubstageMaterialBasedEmissions,
totalSubstageTransportationBasedEmissions }"]
L1 --> M[Stages Level Calculation]
M --> N[Sum emissions for all substages in stage]
N --> O[Output stage emissions]
O --> O1["{ totalStageEmissions,
totalStageMaterialBasedEmissions,
totalStageTransportationBasedEmissions }"]
O1 --> P[Batch Level Calculation]
P --> Q[Sum emissions for all stages in batch]
Q --> R[Output batch emissions]
R --> R1["{ timestamp,
totalBatchEmissions,
totalBatchMaterialBasedEmissions,
totalBatchTransportationBasedEmissions }"]
end
R1 --> S[End]
```