Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/forcing data #31

Merged
merged 33 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
709b8a6
Add forcing data structs
ar-siddiqui May 27, 2022
7a9e74b
Separate forcing files
ar-siddiqui May 30, 2022
0af4420
Add endpoint and handler
ar-siddiqui May 31, 2022
87baef4
Get unsteady boundary condition names
ar-siddiqui May 31, 2022
531b296
Create framework for scanning only one time
ar-siddiqui May 31, 2022
33b00d7
Extract flow hydrograph
ar-siddiqui May 31, 2022
61ab551
Update readme
ar-siddiqui Jun 1, 2022
7a7c5e0
Update anothrNick tag #patch
ar-siddiqui Jun 1, 2022
5375382
Return more hydrograph data
ar-siddiqui Jun 1, 2022
b17e653
Extract lateral, groundwater, uniform-lateral
ar-siddiqui Jun 1, 2022
7806f49
Extract stage and stage-flow hydrograph
ar-siddiqui Jun 2, 2022
07e8df7
Setup RC extraction
ar-siddiqui Jun 2, 2022
fbe4420
extract rating curve
justinjpaul Jun 2, 2022
f8836cb
move RC data collection to separate function
justinjpaul Jun 3, 2022
4148fc7
make structured functions to parse hydrograph data
justinjpaul Jun 3, 2022
fde03f7
Merge pull request #23 from Dewberry/feature/forcing-data-justin
ar-siddiqui Jun 3, 2022
bfcd8fe
add numVals check
justinjpaul Jun 6, 2022
99ca3ba
Extract steady data
ar-siddiqui Jun 6, 2022
f63e838
Merge branch 'feature/forcing-data-justin' of github.com:Dewberry/mca…
ar-siddiqui Jun 6, 2022
1d19e5f
Rename BCHeader funcs
ar-siddiqui Jun 6, 2022
318d164
Fix erros for steady data
ar-siddiqui Jun 6, 2022
cb15a6f
extract ib stage flow, gates, rules
justinjpaul Jun 9, 2022
f6828dc
Merge branch 'feature/forcing-data-justin' of github.com:Dewberry/mca…
ar-siddiqui Jun 13, 2022
497dfbd
Fix Gate Data function
ar-siddiqui Jun 13, 2022
416a9a0
Extract dss file and path
ar-siddiqui Jun 13, 2022
8d077f8
Add Not Implemented data
ar-siddiqui Jun 13, 2022
85cedb8
Add code documentation
ar-siddiqui Jun 13, 2022
6f250a2
Add flow title and program version to unsteady
ar-siddiqui Jun 13, 2022
3fac174
Rework logic to parse flow title and version
ar-siddiqui Jun 14, 2022
3469b17
Add comment for description
ar-siddiqui Jun 14, 2022
71ecead
extract storage elevations
justinjpaul Jun 14, 2022
59709cc
Merge pull request #32 from Dewberry/feature/forcing-data-justin
ar-siddiqui Jun 14, 2022
92680d6
Fix empty steady flow values
ar-siddiqui Jun 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ jobs:
- name: Bump a new Release and update Version
uses: actions/checkout@v2
with:
fetch-depth: "0"
fetch-depth: '0'
- name: Bump version and push tag
uses: anothrNick/github-tag-action@1.26.0
uses: anothrNick/github-tag-action@1.39.0
id: update-tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
41 changes: 22 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,47 @@
# mcat-ras

Contains the HEC-RAS model content and analysis tool (MCAT). Given a .prj file, this MCAT identifies paths to the plan, forcing, and geometry files and extracts the model's metadata and geospatial data.

The MCAT includes:

- a standard set of methods to evaluate a model's content:
- isamodel
- modeltype
- modelversion
- index
- isgeospatial
- geospatialdata
- isamodel
- modeltype
- modelversion
- index
- isgeospatial
- geospatialdata
- forcingdata
- an API for executing the above methods.
- a docker container for running the methods and API.

## Contents

## Contents
- `/config`: contains the data structure that holds the config information for the API.
- `/docs`: contains the auto-generated swagger files.
- `/handlers`: contains the handler function for each API endpoint.
- `/tools`: the core code used to extract information from the various HEC-RAS files.
- `docker-compose.yml`: options for building the dockerfile.
- `main.go` : API Server.


### Getting Started

---

- Add a .env file to the root level of this directory with the following structure:
```
AWS_ACCESS_KEY_ID='**************'
AWS_SECRET_ACCESS_KEY='**************'
AWS_DEFAULT_REGION='us-east-1'
S3_BUCKET='******'
```
```
AWS_ACCESS_KEY_ID='**************'
AWS_SECRET_ACCESS_KEY='**************'
AWS_DEFAULT_REGION='us-east-1'
S3_BUCKET='******'
```
- Run `docker-compose up`
- To teardown, run `docker-compose down`


### MCAT REST Specification

---

The following requests can be used to interrogate a model whose storage location is defined by the s3_key parameter:

`GET /isamodel?definition_file=<s3_key>`
Expand All @@ -52,15 +56,14 @@ The following requests can be used to interrogate a model whose storage location

`GET /geospatialdata?definition_file=<s3_key>`

`GET /forcingdata?definition_file=<s3_key>`

*For example: `http://mcat-ras:5600/isamodel?definition_file=models/ras/CHURCH HOUSE GULLY/CHURCH HOUSE GULLY.prj`*

_For example: `http://mcat-ras:5600/isamodel?definition_file=models/ras/CHURCH HOUSE GULLY/CHURCH HOUSE GULLY.prj`_

### Swagger Documentation:

---

To view docs goto: http://localhost:5600/swagger/index.html


![](docs/swagger_image.png)
![](docs/swagger_image.png)
74 changes: 74 additions & 0 deletions handlers/forcingdata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package handlers

import (
"fmt"
"net/http"
"path/filepath"

"app/config"
"app/tools"

"github.com/USACE/filestore"
"github.com/go-errors/errors" // warning: replaces standard errors
"github.com/labstack/echo/v4"
)

// ForcingData godoc
// @Summary Extract forcing data from flow files
// @Description forcing data from a RAS model given an s3 key
// @Tags MCAT
// @Accept json
// @Produce json
// @Param definition_file query string true "/models/ras/CHURCH HOUSE GULLY/CHURCH HOUSE GULLY.prj"
// @Success 200 {object} interface{}
// @Failure 500 {object} SimpleResponse
// @Router /forcingdata [get]
func ForcingData(ac *config.APIConfig) echo.HandlerFunc {
return func(c echo.Context) error {

definitionFile := c.QueryParam("definition_file")
if definitionFile == "" {
return c.JSON(http.StatusBadRequest, "Missing query parameter: `definition_file`")
}

if !isAModel(ac.FileStore, definitionFile) {
return c.JSON(http.StatusBadRequest, definitionFile+" is not a valid RAS prj file.")
}

data, err := forcingData(definitionFile, ac.FileStore)
if err != nil {
return c.JSON(http.StatusInternalServerError, SimpleResponse{http.StatusInternalServerError, fmt.Sprintf("Go error encountered: %v", err.Error()), err.(*errors.Error).ErrorStack()})
}

return c.JSON(http.StatusOK, data)
}
}

func forcingData(definitionFile string, fs *filestore.FileStore) (tools.ForcingData, error) {
fd := tools.ForcingData{
Steady: make(map[string]tools.SteadyData),
Unsteady: make(map[string]tools.UnsteadyData),
}

mfiles, err := modFiles(definitionFile, *fs)
if err != nil {
return fd, errors.Wrap(err, 0)
}

for _, fp := range mfiles {

ext := filepath.Ext(fp)

switch {

case tools.RasRE.AllFlow.MatchString(ext):

if err := tools.GetForcingData(&fd, *fs, fp); err != nil {
return fd, errors.Wrap(err, 0)
}

}
}

return fd, nil
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func main() {
e.GET("/index", handlers.Index(appConfig.FileStore))
e.GET("/isgeospatial", handlers.IsGeospatial(appConfig.FileStore))
e.GET("/geospatialdata", handlers.GeospatialData(appConfig))
e.GET("/forcingdata", handlers.ForcingData(appConfig))

// pgdb endpoints
e.POST("/upsert/model", pgdb.UpsertRasModel(appConfig, dbConfig))
Expand Down
41 changes: 41 additions & 0 deletions tools/forcing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Structs and functions used to parse all [steady, unsteady, quasi-unsteady] types of flow files.

package tools

import (
"path/filepath"

"github.com/USACE/filestore"
)

// Main struct for focing data.
type ForcingData struct {
Steady map[string]SteadyData `json:"Steady,omitempty"`
QuasiUnsteady map[string]interface{} `json:"QuasiUnsteady,omitempty"` // to be implemented
Unsteady map[string]UnsteadyData `json:"Unsteady,omitempty"`
}

// Boundary Condition.
type BoundaryCondition struct {
RS string `json:",omitempty"` // only exists for unsteady rivers
BCLine string `json:"bc_line,omitempty"` // only exists for unsteady storage and 2D areas
Description string `json:"description,omitempty"` // only exists for Rules, not implemented yet
Type string `json:"type"`
Data interface{} `json:"data"`
}

// Get Forcing Data from steady, unsteady or quasi-steady flow file.
func GetForcingData(fd *ForcingData, fs filestore.FileStore, flowFilePath string) (err error) {
extPrefix := filepath.Ext(flowFilePath)[0:2]

if extPrefix == ".f" {
err = getSteadyData(fd, fs, flowFilePath)
} else if extPrefix == ".u" {
err = getUnsteadyData(fd, fs, flowFilePath)
} else if extPrefix == ".q" {
flowFileName := filepath.Base(flowFilePath)
fd.QuasiUnsteady[flowFileName] = "Not Implemented"
}

return err
}
49 changes: 0 additions & 49 deletions tools/geospatial.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"math"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/USACE/filestore"
Expand Down Expand Up @@ -64,54 +63,6 @@ func checkUnitConsistency(modelUnits string, sourceCRS string) error {
return errors.New("Unable to check unit consistency, could not identify the coordinate reference system's units")
}

func dataPairsfromTextBlock(sc *bufio.Scanner, nPairs int, colWidth int, valueWidth int) ([][2]float64, error) {
var stride int = valueWidth * 2
pairs := [][2]float64{}
out:
for sc.Scan() {
line := sc.Text()
for s := 0; s < colWidth; {
if len(line) > s {
val1, err := parseFloat(strings.TrimSpace(line[s:s+valueWidth]), 64)
if err != nil {
return pairs, errors.Wrap(err, 0)
}
val2, err := parseFloat(strings.TrimSpace(line[s+valueWidth:s+stride]), 64)
if err != nil {
return pairs, errors.Wrap(err, 0)
}
pairs = append(pairs, [2]float64{val1, val2})
if len(pairs) == nPairs {
break out
}
} else {
break
}
s += stride
}
}
return pairs, nil
}

func getDataPairsfromTextBlock(nDataPairsLine string, sc *bufio.Scanner, colWidth int, valueWidth int) ([][2]float64, error) {
pairs := [][2]float64{}
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, nDataPairsLine) {
nPairs, err := strconv.Atoi(rightofEquals(line))
if err != nil {
return pairs, errors.Wrap(err, 0)
}
pairs, err = dataPairsfromTextBlock(sc, nPairs, colWidth, valueWidth)
if err != nil {
return pairs, errors.Wrap(err, 0)
}
break
}
}
return pairs, nil
}

// distance returns the distance along a straight line in euclidean space
func distance(p0, p1 [2]float64) float64 {
result := math.Sqrt(math.Pow((p1[0]-p0[0]), 2) + math.Pow((p1[1]-p0[1]), 2))
Expand Down
Loading