R wrapper for Gradle tasks of OML projects
This package allows users to run Gradle tasks of OML projects from R. Note: Only Mac OS has been tested.
OML projects created by openCAESAR are Gradle projects that have OML analysis tools configured as Gradle tasks in a build.gradle script. A user can invoke Gradle tasks from a console/terminal session using the Gradle Wrapper Command-Line Interface (e.g., ./gradlew owlLoad). The supported OML editors such as OML Rosetta and OML Luxor allow invoking those Gradle tasks using a UI.
In the MBSE practice using openCAESAR, the vocabularies are described to answer analysis questions. Typically, the process is iterative. Build OML vocabularies and descriptions, write queries in the SPARQL language for analysis, and modify the model based on the query results in an exploratory manner.
This package aims to improve the reproducibility of the exploratory modeling process with documentation tools such as R Markdown and Quarto.
You can install the development version of “omlhashiR” from GitHub with:
library(devtools)
install_github("UTNAK/omlhashiR")
Here is an example OML project called Kepler 16b. For details, check this tutorial.
git clone https://github.com/opencaesar/kepler16b-example.git
library(omlhashiR)
oml_repository <- "./kepler16b-example"
./gradlew clean
oml_clean(oml_repository)
#> [1] "> Task :clean" ""
#> [3] "BUILD SUCCESSFUL in 1s" "1 actionable task: 1 executed"
./gradlew build
oml_build(oml_repository)
#> [1] "> Task :omlZip" "> Task :assemble"
#> [3] "> Task :downloadDependencies" "> Task :omlToOwl"
#> [5] "> Task :owlReason" "> Task :check"
#> [7] "> Task :build" ""
#> [9] "BUILD SUCCESSFUL in 4s" "4 actionable tasks: 4 executed"
./gradlew owlLoad
oml_owlLoad(oml_repository)
#> [1] "> Task :downloadDependencies UP-TO-DATE"
#> [2] "> Task :omlToOwl UP-TO-DATE"
#> [3] "> Task :owlReason UP-TO-DATE"
#> [4] "> Task :startFuseki UP-TO-DATE"
#> [5] "> Task :owlLoad"
#> [6] ""
#> [7] "BUILD SUCCESSFUL in 1s"
#> [8] "5 actionable tasks: 1 executed, 4 up-to-date"
./gradlew owlReason
oml_owlReason(oml_repository)
#> [1] "> Task :downloadDependencies UP-TO-DATE"
#> [2] "> Task :omlToOwl UP-TO-DATE"
#> [3] "> Task :owlReason UP-TO-DATE"
#> [4] ""
#> [5] "BUILD SUCCESSFUL in 600ms"
#> [6] "3 actionable tasks: 3 up-to-date"
./gradlew owlQuery
oml_owlQuery(oml_repository)
#> [1] "> Task :downloadDependencies UP-TO-DATE"
#> [2] "> Task :omlToOwl UP-TO-DATE"
#> [3] "> Task :owlReason UP-TO-DATE"
#> [4] "> Task :startFuseki UP-TO-DATE"
#> [5] "> Task :owlLoad UP-TO-DATE"
#> [6] "> Task :owlQuery"
#> [7] ""
#> [8] "BUILD SUCCESSFUL in 715ms"
#> [9] "6 actionable tasks: 1 executed, 5 up-to-date"
./gradlew startFuseki
oml_startFuseki(oml_repository)
#> [1] "> Task :startFuseki UP-TO-DATE" ""
#> [3] "BUILD SUCCESSFUL in 515ms" "1 actionable task: 1 up-to-date"
./gradlew stopFuseki
oml_stopFuseki(oml_repository)
#> [1] ""
#> [2] "> Task :stopFuseki"
#> [3] "Fuseki server with pid=13161 has been stopped"
#> [4] ""
#> [5] "BUILD SUCCESSFUL in 522ms"
#> [6] "1 actionable task: 1 executed"
./gradlew --stop
oml_stop_Daemon(oml_repository)
#> [1] "Stopping Daemon(s)" "1 Daemon stopped"
This process is not a gradle task but we often use this for killing existing fuseki server PIDs. When Fuseki server has failed to start, this command helps to solve the issue in some case.
oml_startFuseki(oml_repository)
#> [1] "Starting a Gradle Daemon, 3 stopped Daemons could not be reused, use --status for details"
#> [2] ""
#> [3] "> Task :startFuseki"
#> [4] "Fuseki server has now successfully started with pid=16851, listening on http://localhost:3030"
#> [5] ""
#> [6] "BUILD SUCCESSFUL in 7s"
#> [7] "1 actionable task: 1 executed"
oml_refresh()
#> [1] "kill success for pid=16851"
We introduce a case study of an exploratory modeling workflows using this package. The figure below shows an overview of the process.
In this case study, we use an example OML project called Kepler 16b. For details, check this tutorial. This case study answers the question of what is the total mass of the spacecraft. The total mass is recalculated when the mass of one subsystem is changed.
We use a package tansakusuR as a wrapper to send SPARQL codes to the endpoint of Kepler 16b.
By using the “omlhashiR” and “tansakusuR” packages, workflows can be seamlessly connected.
library(devtools)
install_github("UTNAK/tansakusuR")
library(omlhashiR)
oml_repository <- "./kepler16b-example"
oml_owlLoad(oml_repository)
#> [1] "> Task :downloadDependencies UP-TO-DATE"
#> [2] "> Task :omlToOwl UP-TO-DATE"
#> [3] "> Task :owlReason UP-TO-DATE"
#> [4] ""
#> [5] "> Task :startFuseki"
#> [6] "Fuseki server has now successfully started with pid=16875, listening on http://localhost:3030"
#> [7] ""
#> [8] "> Task :owlLoad"
#> [9] ""
#> [10] "BUILD SUCCESSFUL in 5s"
#> [11] "5 actionable tasks: 2 executed, 3 up-to-date"
Before we send the SPARQL query codes, we need to set the endpoint url. We can see the endpoint url of the “kepler16b-example” project from http://localhost:3030 as shown below.
Here we set the endpoint_url.
library(tansakusuR)
endpoint_url <- "http://localhost:3030/tutorial2/sparql"
Below is query codes that extract components and containment relations.
query_string <-'
PREFIX base: <http://example.com/tutorial2/vocabulary/base#>
PREFIX mission: <http://example.com/tutorial2/vocabulary/mission#>
PREFIX vim4: <http://bipm.org/jcgm/vim4#>
SELECT DISTINCT ?c1_id ?c1_name ?c1_mass ?c2_id ?c2_name
WHERE {
?c1 a mission:Component ;
base:hasIdentifier ?c1_id ;
base:hasCanonicalName ?c1_name .
OPTIONAL {
?c1 base:isContainedIn ?c2 .
?c2 base:hasIdentifier ?c2_id ;
base:hasCanonicalName ?c2_name .
}
}
ORDER BY ?c1_id ?c2_id
'
We can send a SPARQL query using tansakusuR::send_query
.
data_frame <- tansakusuR::send_query(endpoint_url,query_string)
We can check the query results as a tabular views as follows.
# visualize dataframe
library(DT)
datatable(data_frame, options = list(pageLength = -1))
Next, we modify the query codes to get mass properties.
query_string2 <-'
PREFIX base: <http://example.com/tutorial2/vocabulary/base#>
PREFIX mission: <http://example.com/tutorial2/vocabulary/mission#>
PREFIX vim4: <http://bipm.org/jcgm/vim4#>
SELECT DISTINCT ?c1_id ?c1_name ?c1_mass ?c2_id ?c2_name
WHERE {
?c1 a mission:Component ;
base:hasIdentifier ?c1_id ;
base:hasCanonicalName ?c1_name .
OPTIONAL {
?c1 base:isContainedIn ?c2 .
?c2 base:hasIdentifier ?c2_id ;
base:hasCanonicalName ?c2_name .
}
OPTIONAL {
?c1_mass_mag vim4:characterizes ?c1 ;
vim4:hasDoubleNumber ?c1_mass .
}
}
ORDER BY ?c1_id ?c2_id
'
data_frame <- tansakusuR::send_query(endpoint_url,query_string2)
datatable(data_frame, options = list(pageLength = -1))
What is a total mass of the Orbiter Spacecraft?
library(dplyr)
#> Warning: package 'dplyr' was built under R version 4.3.1
#>
#> Attaching package: 'dplyr'
#> The following object is masked from 'package:tansakusuR':
#>
#> show_query
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
df <- data_frame %>%
filter(c2_name == "Orbiter Spacecraft") %>%
select(c1_id, c1_name, c1_mass) %>%
mutate(c1_mass = as.integer(c1_mass))
total_mass <- sum(df$c1_mass)
total_mass
#> [1] 1957
Next, we modify the mass property of the Orbiter GN&C Subsystem from 156.0 kg to 200.0 kg in “src/oml/example.com/tutorials/description/masses.oml”.
Then we run the owlLoad
task to update the data on our fuseki server.
oml_owlLoad(oml_repository)
#> [1] "> Task :downloadDependencies UP-TO-DATE"
#> [2] "> Task :omlToOwl UP-TO-DATE"
#> [3] "> Task :owlReason UP-TO-DATE"
#> [4] "> Task :startFuseki UP-TO-DATE"
#> [5] "> Task :owlLoad UP-TO-DATE"
#> [6] ""
#> [7] "BUILD SUCCESSFUL in 719ms"
#> [8] "5 actionable tasks: 5 up-to-date"
Now we send our SPARQL query codes again to check the update.
data_frame <- tansakusuR::send_query(endpoint_url,query_string2)
datatable(data_frame, options = list(pageLength = -1))
What is a total mass of the Orbiter Spacecraft?
library(dplyr)
df <- data_frame %>%
filter(c2_name == "Orbiter Spacecraft") %>%
select(c1_id, c1_name, c1_mass) %>%
mutate(c1_mass = as.integer(c1_mass))
total_mass <- sum(df$c1_mass)
total_mass
#> [1] 2001
We demonstrated a case study of documenting the trial and error of the modeling process in a reproducible manner using R Markdown documentation. omlhashiRis a wrapper for executing gradle tasks from R. tansakusuR is a wrapper for sending SPARQL codes to the endpoint from R.