Automatic push from FunctionsAPI
This commit is contained in:
parent
9c6545bd40
commit
a46b9aadea
3423
Cargo.lock
generated
Normal file
3423
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
edition = "2024"
|
||||
name = "web"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
fathom-function = { git = "ssh://git@github.com/fathom-io/pipeline-calculations.git", branch = "main" }
|
||||
pipeline-application = { git = "ssh://git@github.com/fathom-io/pipeline-calculations.git", branch = "main" }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread"] }
|
||||
uuid = { version = "1" }
|
||||
124
README.md
124
README.md
@ -1,2 +1,124 @@
|
||||
# 9484559dec3a43e2864ea14aff2cbeec
|
||||
# Dynamic segmentation function
|
||||
|
||||
A function that exposes the dynamic segmentation algorithm for the pipeline use
|
||||
case.
|
||||
|
||||
This function will recompute the segmentation for all pipelines based on the
|
||||
provided segmentation configuration
|
||||
|
||||
Segmentation is the process of taking local data, crossings, and facilities on
|
||||
the pipeline and creating pipeline segments where this local data changes (a
|
||||
cut line).
|
||||
|
||||
In fathom we support dynamic segmentation where the user is able to configure
|
||||
the properties they would like to consider when segmentizing and to support
|
||||
re-segmentizing the pipeline at any point such as when new data is available
|
||||
from an ILI report.
|
||||
|
||||
Segmentation can be dynamically configured to consider the following properties
|
||||
|
||||
- pipeline diameter (currently required)
|
||||
- wall thickness (currently required)
|
||||
- material grade
|
||||
- coating type
|
||||
- design factor
|
||||
- high consequence area
|
||||
- unusual sensitive area
|
||||
- join type
|
||||
- soil type
|
||||
- soil ph
|
||||
|
||||
Additionally the following crossing types can be considered
|
||||
|
||||
- Road
|
||||
- River
|
||||
- Railroad
|
||||
- Overhead
|
||||
- Highway
|
||||
- Pipeline
|
||||
|
||||
Finally, the following facilities can also be used to create cut lines
|
||||
|
||||
- Valves
|
||||
- Insulation joints
|
||||
- Repairs
|
||||
|
||||
The user is able to configure which the the local properties and which of the
|
||||
crossing and facility types they would like to consider for creating the
|
||||
segmentation. For the purpose of the analytics required later in the process we
|
||||
require the user segments on diameter and wall thickness. The other properties
|
||||
are optional.
|
||||
|
||||
## Example
|
||||
|
||||
```none
|
||||
diameter ├──────────────────────────┼────────────────────────────────────┤
|
||||
40 inch 42 inch
|
||||
wall thickness ├───────┼─────────────────────────────────────────────────┼─────┤
|
||||
12.0 9.0 12.0
|
||||
material grade ├──────────────────────────┼──────────────────────────────┼─────┤
|
||||
L290 L320
|
||||
design factor ├─────────────────────────────────────────────────────────┼─────┤
|
||||
L72
|
||||
road crossing ├──┤ ├──┤
|
||||
river crossing ├──┤ ├──┤
|
||||
valve │ │
|
||||
repair ├─┤
|
||||
|
||||
|
||||
segments ├─┼──┼──┼──────────┼──┼────┼────┼─┼──────────┼──┼──┼──┼───┼──┼──┤
|
||||
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
```
|
||||
|
||||
## Input
|
||||
|
||||
### Arguments
|
||||
|
||||
- `org_id`: as string which should be a valid `uuid` for the organization
|
||||
- `project_id`: the id of the data project where the pipeline data is found
|
||||
- `facilities`: an array of `string` each value should be one of
|
||||
- `insulation_joint`
|
||||
- `repair`
|
||||
- `valve`.
|
||||
- `crossings`: an object with key for each supported crossing type and values
|
||||
as objects representing the selected values
|
||||
- `local_data`: an array of `string` each value should be one of
|
||||
- `material_grade`
|
||||
- `coating_type`
|
||||
- `design_factor`
|
||||
- `high_consequence_area`
|
||||
- `unusual_sensitive_area`
|
||||
- `joint_type`
|
||||
- `soil_type`
|
||||
- `soil_ph`
|
||||
|
||||
## Creating the function on the platform
|
||||
|
||||
To create this function on the platform using the `cli` set up the port forwarding as shown in README.
|
||||
|
||||
Then run the following command to create the function.
|
||||
|
||||
```bash
|
||||
cargo run functions create \
|
||||
-f functions/segmentation \
|
||||
-d "Runs the segmentation algorithm for the provided pipelines" \
|
||||
-i org_id=string \
|
||||
-i project_id=string \
|
||||
-i facilities=array \
|
||||
-i crossings=object \
|
||||
-i local_data=array
|
||||
```
|
||||
|
||||
## Testing the function locally
|
||||
|
||||
You can run and test the function locally by running
|
||||
|
||||
```bash
|
||||
cargo run
|
||||
```
|
||||
|
||||
Then you can check it work with `curl` as follows
|
||||
|
||||
```bash
|
||||
curl localhost:8080 -d $(jq '. | tojson' functions/segmentation/example_input.json)
|
||||
```
|
||||
|
||||
80
example_input.json
Normal file
80
example_input.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"facilities": [],
|
||||
"local_data": [
|
||||
"material_grade",
|
||||
"coating_type",
|
||||
"design_factor",
|
||||
"high_consequence_area",
|
||||
"unusual_sensitive_area",
|
||||
"joint_type",
|
||||
"soil_type",
|
||||
"soil_ph"
|
||||
],
|
||||
"org_id": "2cbfe270-d195-48ad-aed1-24145924635c",
|
||||
"pipeline_id": [
|
||||
"01966d47-1d4c-7751-a1f1-0617caa3a00d"
|
||||
],
|
||||
"project_id": "680b61b0aedd6f9e639d8699",
|
||||
"crossings": {
|
||||
"highway": {
|
||||
"longer_than": {
|
||||
"inputType": "number",
|
||||
"value": null
|
||||
},
|
||||
"selected": {
|
||||
"inputType": "checkbox",
|
||||
"value": null
|
||||
}
|
||||
},
|
||||
"overhead": {
|
||||
"longer_than": {
|
||||
"inputType": "number",
|
||||
"value": null
|
||||
},
|
||||
"selected": {
|
||||
"inputType": "checkbox",
|
||||
"value": true
|
||||
}
|
||||
},
|
||||
"pipeline": {
|
||||
"longer_than": {
|
||||
"inputType": "number",
|
||||
"value": null
|
||||
},
|
||||
"selected": {
|
||||
"inputType": "checkbox",
|
||||
"value": null
|
||||
}
|
||||
},
|
||||
"railroad": {
|
||||
"longer_than": {
|
||||
"inputType": "number",
|
||||
"value": null
|
||||
},
|
||||
"selected": {
|
||||
"inputType": "checkbox",
|
||||
"value": null
|
||||
}
|
||||
},
|
||||
"river": {
|
||||
"longer_than": {
|
||||
"inputType": "number",
|
||||
"value": null
|
||||
},
|
||||
"selected": {
|
||||
"inputType": "checkbox",
|
||||
"value": null
|
||||
}
|
||||
},
|
||||
"road": {
|
||||
"longer_than": {
|
||||
"inputType": "number",
|
||||
"value": 10
|
||||
},
|
||||
"selected": {
|
||||
"inputType": "checkbox",
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
135
src/main.rs
Normal file
135
src/main.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use fathom_function::forms::TableCellValue;
|
||||
use fathom_function::tracing;
|
||||
use pipeline_application::application::{
|
||||
Application, CrossingConfiguration, CrossingKind, FacilityType, SegmentationConfiguration,
|
||||
uom::si::f64::Length, uom::si::length::meter,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[fathom_function::function]
|
||||
async fn segment(input: Input) -> Result<Output, String> {
|
||||
let app = Application::new_from_compile_env(input.org_id, input.project_id).unwrap();
|
||||
|
||||
for pipeline_id in input.pipeline_id {
|
||||
app.segment(pipeline_id, &input.configuration)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
tracing::error!(%pipeline_id, ?err, "Error running segmentation algorithm");
|
||||
format!("{err:?}")
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(Output {
|
||||
status: "Success".to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct Output {
|
||||
status: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Input {
|
||||
org_id: Uuid,
|
||||
project_id: String,
|
||||
pipeline_id: Vec<Uuid>,
|
||||
#[serde(flatten)]
|
||||
configuration: Configuration,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Configuration {
|
||||
facilities: Vec<FacilityType>,
|
||||
local_data: Vec<String>,
|
||||
crossings: Crossings,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Crossings {
|
||||
highway: CrossingRow,
|
||||
road: CrossingRow,
|
||||
river: CrossingRow,
|
||||
railroad: CrossingRow,
|
||||
overhead: CrossingRow,
|
||||
pipeline: CrossingRow,
|
||||
}
|
||||
|
||||
impl Crossings {
|
||||
fn to_crossing_configurations(&self) -> impl Iterator<Item = CrossingConfiguration> {
|
||||
[
|
||||
self.highway
|
||||
.to_crossing_configuration(CrossingKind::Highway),
|
||||
self.road.to_crossing_configuration(CrossingKind::Road),
|
||||
self.river.to_crossing_configuration(CrossingKind::River),
|
||||
self.railroad
|
||||
.to_crossing_configuration(CrossingKind::Railroad),
|
||||
self.overhead
|
||||
.to_crossing_configuration(CrossingKind::Overhead),
|
||||
self.pipeline
|
||||
.to_crossing_configuration(CrossingKind::Pipeline),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct CrossingRow {
|
||||
longer_than: TableCellValue,
|
||||
selected: TableCellValue,
|
||||
}
|
||||
|
||||
impl CrossingRow {
|
||||
fn to_crossing_configuration(
|
||||
&self,
|
||||
crossing_kind: CrossingKind,
|
||||
) -> Option<CrossingConfiguration> {
|
||||
if (&self.selected).try_into().unwrap_or(false) {
|
||||
Some(CrossingConfiguration {
|
||||
crossing_kind,
|
||||
longer_than: Length::new::<meter>(
|
||||
(&self.longer_than).try_into().ok().unwrap_or(0.0),
|
||||
),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Configuration> for SegmentationConfiguration {
|
||||
fn from(value: &Configuration) -> Self {
|
||||
let mut config = Self::default_false();
|
||||
config = value
|
||||
.facilities
|
||||
.iter()
|
||||
.fold(config, |config, fac| match fac {
|
||||
FacilityType::InsulationJoint => config.by_insulation_joints(true),
|
||||
FacilityType::Repair => config.by_repairs(true),
|
||||
FacilityType::Valve => config.by_valves(true),
|
||||
_ => config,
|
||||
});
|
||||
|
||||
config = value.crossings.to_crossing_configurations().fold(
|
||||
config,
|
||||
SegmentationConfiguration::with_crossing_configuration,
|
||||
);
|
||||
|
||||
value
|
||||
.local_data
|
||||
.iter()
|
||||
.fold(config, |config, loc| match loc.as_str() {
|
||||
"material_grade" => config.by_material_grade(true),
|
||||
"coating_type" => config.by_coating_type(true),
|
||||
"design_factor" => config.by_design_factor(true),
|
||||
"high_consequence_area" => config.by_high_consequence_area(true),
|
||||
"unusual_sensitive_area" => config.by_unusual_sensitive_area(true),
|
||||
"joint_type" => config.by_joint_type(true),
|
||||
"soil_type" => config.by_soil_type(true),
|
||||
"soil_ph" => config.by_soil_ph(true),
|
||||
_ => config,
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user