Task 202: .F01 File Format

Task .F01 File Format

1. List of Properties of the .F01 File Format Intrinsic to Its File System

Based on the specifications for the .F01 file format, which is a text-based file used by the HEC-RAS software for storing steady flow data in hydraulic modeling, the intrinsic properties are the following fields and structures embedded in the file. These are parsed from keyword-based lines in ASCII text format, typically including headers, numerical values, and optional sections. The format is not binary but structured text, with properties such as:

  • Flow Title: A string describing the purpose or name of the flow data set.
  • Number of Profiles: An integer indicating the number of flow profiles (e.g., different flow events like 10-year or 100-year floods).
  • Profile Names: A list of strings naming each profile (e.g., "PF 1", "10 Year Profile").
  • River and Reach Names: Strings identifying the river system and specific reaches (e.g., "Main River", "Reach1").
  • Number of River Stations: An integer specifying the number of cross-section stations along the reaches.
  • Flow Values: Numerical values (floats or integers) for discharge at each reach and station for every profile.
  • Boundary Conditions: Details on upstream and downstream conditions, including type (e.g., "Normal Depth", "Known WSE"), values (e.g., slope or elevation), and application (per profile or all).
  • Observed Data: Optional list of observed water surface elevations at specific river stations for calibration.
  • Gate Openings: Optional settings for structures, including number of gates, opening heights, and number opened per profile.

These properties are intrinsic to the file's structure, allowing the HEC-RAS system to read and apply flow data in simulations.

After extensive search, direct download links to individual .F01 files are not readily available in public domains, as they are typically bundled in project zips or generated by HEC-RAS software. However, .F01 files can be obtained from official HEC-RAS example projects. The following are direct links to zip archives containing multiple .F01 files (e.g., from steady flow examples):

Extract the zips to access the .F01 files.

3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .F01 File Dump

The following is a self-contained HTML snippet with embedded JavaScript that can be embedded in a Ghost blog post. It allows users to drag and drop a .F01 file, parses the text content based on the format specifications, extracts the properties, and dumps them to the screen in a structured display.

Drag and drop a .F01 file here

4. Python Class for .F01 File Handling

The following Python class can open, decode (parse), read, write, and print the properties of a .F01 file to the console.

class F01Handler:
    def __init__(self, filepath=None):
        self.properties = {}
        if filepath:
            self.read(filepath)

    def read(self, filepath):
        with open(filepath, 'r') as f:
            content = f.read()
        lines = content.split('\n')
        for line in lines:
            if line.startswith('Flow Title:'):
                self.properties['Flow Title'] = line.split(':')[1].strip()
            elif line.startswith('Number of Profiles:'):
                self.properties['Number of Profiles'] = int(line.split(':')[1].strip())
            elif line.startswith('Profile Names:'):
                self.properties['Profile Names'] = [name.strip() for name in line.split(':')[1].split(',')]
            elif line.startswith('River Rch='):
                self.properties.setdefault('River and Reach Names', []).append(line.split('=')[1].strip())
            elif line.startswith('Number of River Stations:'):
                self.properties['Number of River Stations'] = int(line.split(':')[1].strip())
            elif line.startswith('Flow Data:'):
                self.properties.setdefault('Flow Values', []).append(float(line.split(':')[1].strip()))
            elif line.startswith('Boundary Condition Lines:'):
                self.properties.setdefault('Boundary Conditions', []).append(line.split(':')[1].strip())
            elif line.startswith('Observed Data:'):
                self.properties.setdefault('Observed Data', []).append(line.split(':')[1].strip())
            elif line.startswith('Gate Openings:'):
                self.properties.setdefault('Gate Openings', []).append(line.split(':')[1].strip())

    def write(self, filepath):
        with open(filepath, 'w') as f:
            for key, value in self.properties.items():
                if isinstance(value, list):
                    f.write(f"{key}: {','.join(map(str, value))}\n")
                else:
                    f.write(f"{key}: {value}\n")

    def print_properties(self):
        for key, value in self.properties.items():
            print(f"{key}: {value}")

# Example usage:
# handler = F01Handler('example.F01')
# handler.print_properties()
# handler.properties['Flow Title'] = 'New Title'
# handler.write('new.F01')

5. Java Class for .F01 File Handling

The following Java class can open, decode (parse), read, write, and print the properties of a .F01 file to the console.

import java.io.*;
import java.util.*;

public class F01Handler {
    private Map<String, Object> properties = new HashMap<>();

    public F01Handler(String filepath) throws IOException {
        if (filepath != null) {
            read(filepath);
        }
    }

    public void read(String filepath) throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("Flow Title:")) {
                    properties.put("Flow Title", line.split(":")[1].trim());
                } else if (line.startsWith("Number of Profiles:")) {
                    properties.put("Number of Profiles", Integer.parseInt(line.split(":")[1].trim()));
                } else if (line.startsWith("Profile Names:")) {
                    properties.put("Profile Names", Arrays.asList(line.split(":")[1].trim().split(",")));
                } else if (line.startsWith("River Rch=")) {
                    List<String> reaches = (List<String>) properties.getOrDefault("River and Reach Names", new ArrayList<>());
                    reaches.add(line.split("=")[1].trim());
                    properties.put("River and Reach Names", reaches);
                } else if (line.startsWith("Number of River Stations:")) {
                    properties.put("Number of River Stations", Integer.parseInt(line.split(":")[1].trim()));
                } else if (line.startsWith("Flow Data:")) {
                    List<Double> flows = (List<Double>) properties.getOrDefault("Flow Values", new ArrayList<>());
                    flows.add(Double.parseDouble(line.split(":")[1].trim()));
                    properties.put("Flow Values", flows);
                } else if (line.startsWith("Boundary Condition Lines:")) {
                    List<String> bcs = (List<String>) properties.getOrDefault("Boundary Conditions", new ArrayList<>());
                    bcs.add(line.split(":")[1].trim());
                    properties.put("Boundary Conditions", bcs);
                } else if (line.startsWith("Observed Data:")) {
                    List<String> obs = (List<String>) properties.getOrDefault("Observed Data", new ArrayList<>());
                    obs.add(line.split(":")[1].trim());
                    properties.put("Observed Data", obs);
                } else if (line.startsWith("Gate Openings:")) {
                    List<String> gates = (List<String>) properties.getOrDefault("Gate Openings", new ArrayList<>());
                    gates.add(line.split(":")[1].trim());
                    properties.put("Gate Openings", gates);
                }
            }
        }
    }

    public void write(String filepath) throws IOException {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filepath))) {
            for (Map.Entry<String, Object> entry : properties.entrySet()) {
                if (entry.getValue() instanceof List) {
                    writer.write(entry.getKey() + ": " + String.join(",", (List<?>) entry.getValue()) + "\n");
                } else {
                    writer.write(entry.getKey() + ": " + entry.getValue() + "\n");
                }
            }
        }
    }

    public void printProperties() {
        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     F01Handler handler = new F01Handler("example.F01");
    //     handler.printProperties();
    //     handler.write("new.F01");
    // }
}

6. JavaScript Class for .F01 File Handling

The following JavaScript class can open (using FileReader), decode (parse), read, write (using Blob for download), and print the properties of a .F01 file to the console. Note: Writing requires browser support for download.

class F01Handler {
  constructor(filepath = null) {
    this.properties = {};
    if (filepath) {
      this.read(filepath);
    }
  }

  read(content) {  // Accepts text content; for file, use FileReader externally
    const lines = content.split('\n');
    lines.forEach(line => {
      if (line.startsWith('Flow Title:')) {
        this.properties['Flow Title'] = line.split(':')[1].trim();
      } else if (line.startsWith('Number of Profiles:')) {
        this.properties['Number of Profiles'] = parseInt(line.split(':')[1].trim());
      } else if (line.startsWith('Profile Names:')) {
        this.properties['Profile Names'] = line.split(':')[1].trim().split(',');
      } else if (line.startsWith('River Rch=')) {
        this.properties['River and Reach Names'] = this.properties['River and Reach Names'] || [];
        this.properties['River and Reach Names'].push(line.split('=')[1].trim());
      } else if (line.startsWith('Number of River Stations:')) {
        this.properties['Number of River Stations'] = parseInt(line.split(':')[1].trim());
      } else if (line.startsWith('Flow Data:')) {
        this.properties['Flow Values'] = this.properties['Flow Values'] || [];
        this.properties['Flow Values'].push(parseFloat(line.split(':')[1].trim()));
      } else if (line.startsWith('Boundary Condition Lines:')) {
        this.properties['Boundary Conditions'] = this.properties['Boundary Conditions'] || [];
        this.properties['Boundary Conditions'].push(line.split(':')[1].trim());
      } else if (line.startsWith('Observed Data:')) {
        this.properties['Observed Data'] = this.properties['Observed Data'] || [];
        this.properties['Observed Data'].push(line.split(':')[1].trim());
      } else if (line.startsWith('Gate Openings:')) {
        this.properties['Gate Openings'] = this.properties['Gate Openings'] || [];
        this.properties['Gate Openings'].push(line.split(':')[1].trim());
      }
    });
  }

  write(filename = 'output.F01') {
    let content = '';
    for (const [key, value] of Object.entries(this.properties)) {
      if (Array.isArray(value)) {
        content += `${key}: ${value.join(',')}\n`;
      } else {
        content += `${key}: ${value}\n`;
      }
    }
    const blob = new Blob([content], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  }

  printProperties() {
    console.log(this.properties);
  }
}

// Example usage:
// const handler = new F01Handler();
// // To read from file: use FileReader to get content, then handler.read(content);
// handler.printProperties();
// handler.write();

7. C Class for .F01 File Handling

Since C does not have native classes, the following is a C++ class that can open, decode (parse), read, write, and print the properties of a .F01 file to the console.

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>

class F01Handler {
private:
    std::map<std::string, std::string> properties;  // Simplified: lists stored as comma-separated strings

public:
    F01Handler(const std::string& filepath = "") {
        if (!filepath.empty()) {
            read(filepath);
        }
    }

    void read(const std::string& filepath) {
        std::ifstream file(filepath);
        if (!file.is_open()) {
            std::cerr << "Error opening file." << std::endl;
            return;
        }
        std::string line;
        while (std::getline(file, line)) {
            if (line.find("Flow Title:") == 0) {
                properties["Flow Title"] = line.substr(11);
            } else if (line.find("Number of Profiles:") == 0) {
                properties["Number of Profiles"] = line.substr(19);
            } else if (line.find("Profile Names:") == 0) {
                properties["Profile Names"] = line.substr(14);
            } else if (line.find("River Rch=") == 0) {
                std::string reaches = properties["River and Reach Names"];
                if (!reaches.empty()) reaches += ",";
                reaches += line.substr(10);
                properties["River and Reach Names"] = reaches;
            } else if (line.find("Number of River Stations:") == 0) {
                properties["Number of River Stations"] = line.substr(25);
            } else if (line.find("Flow Data:") == 0) {
                std::string flows = properties["Flow Values"];
                if (!flows.empty()) flows += ",";
                flows += line.substr(10);
                properties["Flow Values"] = flows;
            } else if (line.find("Boundary Condition Lines:") == 0) {
                std::string bcs = properties["Boundary Conditions"];
                if (!bcs.empty()) bcs += ",";
                bcs += line.substr(25);
                properties["Boundary Conditions"] = bcs;
            } else if (line.find("Observed Data:") == 0) {
                std::string obs = properties["Observed Data"];
                if (!obs.empty()) obs += ",";
                obs += line.substr(14);
                properties["Observed Data"] = obs;
            } else if (line.find("Gate Openings:") == 0) {
                std::string gates = properties["Gate Openings"];
                if (!gates.empty()) gates += ",";
                gates += line.substr(14);
                properties["Gate Openings"] = gates;
            }
        }
        file.close();
    }

    void write(const std::string& filepath) {
        std::ofstream file(filepath);
        if (!file.is_open()) {
            std::cerr << "Error opening file for writing." << std::endl;
            return;
        }
        for (const auto& pair : properties) {
            file << pair.first << ": " << pair.second << std::endl;
        }
        file.close();
    }

    void printProperties() {
        for (const auto& pair : properties) {
            std::cout << pair.first << ": " << pair.second << std::endl;
        }
    }
};

// Example usage:
// int main() {
//     F01Handler handler("example.F01");
//     handler.printProperties();
//     handler.write("new.F01");
//     return 0;
// }