{"id":32151850,"url":"https://github.com/patrick-zippenfenig/swiftnetcdf","last_synced_at":"2026-03-06T06:31:07.748Z","repository":{"id":39637324,"uuid":"207091679","full_name":"patrick-zippenfenig/SwiftNetCDF","owner":"patrick-zippenfenig","description":"Read and write NetCDF files in Swift","archived":false,"fork":false,"pushed_at":"2025-07-14T13:43:36.000Z","size":154,"stargazers_count":18,"open_issues_count":2,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-21T10:54:11.344Z","etag":null,"topics":["netcdf","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/patrick-zippenfenig.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-09-08T09:46:17.000Z","updated_at":"2025-10-18T12:00:11.000Z","dependencies_parsed_at":"2025-04-01T08:28:19.349Z","dependency_job_id":"27c86c5c-3b52-4af4-b600-107adf6dc82f","html_url":"https://github.com/patrick-zippenfenig/SwiftNetCDF","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/patrick-zippenfenig/SwiftNetCDF","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrick-zippenfenig%2FSwiftNetCDF","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrick-zippenfenig%2FSwiftNetCDF/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrick-zippenfenig%2FSwiftNetCDF/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrick-zippenfenig%2FSwiftNetCDF/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/patrick-zippenfenig","download_url":"https://codeload.github.com/patrick-zippenfenig/SwiftNetCDF/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrick-zippenfenig%2FSwiftNetCDF/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280248570,"owners_count":26297925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["netcdf","swift"],"created_at":"2025-10-21T10:54:09.808Z","updated_at":"2025-10-21T10:54:11.720Z","avatar_url":"https://github.com/patrick-zippenfenig.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwiftNetCDF\n![Swift 5](https://img.shields.io/badge/Swift-5-orange.svg) ![SPM](https://img.shields.io/badge/SPM-compatible-green.svg) ![Platforms](https://img.shields.io/badge/Platforms-macOS%20Linux-green.svg) [![codebeat badge](https://codebeat.co/badges/cca7b706-6c03-4b0a-ad0b-f730563e0ef5)](https://codebeat.co/projects/github-com-patrick-zippenfenig-swiftnetcdf-master) [![Test](https://github.com/patrick-zippenfenig/SwiftNetCDF/actions/workflows/test.yml/badge.svg)](https://github.com/patrick-zippenfenig/SwiftNetCDF/actions/workflows/test.yml)\n\nSwiftNetCDF is a library to read and write NetCDF files in Swift with type safety.\n\n## Installation\n1. SwiftNetCDF requires the NetCDF C client library which can be installed on Mac with `brew install netcdf` or on Linux with `sudo apt install libnetcdf-dev`.\n\n2. Add `SwiftNetCDF` as a dependency to your `Package.swift`\n\n```swift\n  dependencies: [\n    .package(url: \"https://github.com/patrick-zippenfenig/SwiftNetCDF.git\", from: \"1.0.0\")\n  ],\n  targets: [\n    .target(name: \"MyApp\", dependencies: [\"SwiftNetCDF\"])\n  ]\n```\n\n3. Build your project:\n\n```bash\n$ swift build\n```\n\n## Usage\n1. Write NetCDF files\n\n```swift\nimport SwiftNetCDF\n\nlet data = [Int32(0), 3, 4, 6, 12, 45, 89, ...]\n\nvar file = try NetCDF.create(path: \"test.nc\", overwriteExisting: true)\n\ntry file.setAttribute(\"TITLE\", \"My data set\")\n\nlet dimensions = [\n  try file.createDimension(name: \"LAT\", length: 10),\n  try file.createDimension(name: \"LON\", length: 5)\n]\n\nlet variable = try file.createVariable(name: \"MyData\", type: Int32.self, dimensions: dimensions)\ntry variable.write(data)\n```\n\n2. Read NetCDF files\n\n```swift\nimport SwiftNetCDF\n\nguard let file = try NetCDF.open(path: \"test.nc\", allowUpdate: false) else {\n    fatalError(\"File test.nc does not exist\")\n}\n\nguard let title: String = try file.getAttribute(\"TITLE\")?.read() else {\n    fatalError(\"TITLE attribute not available or not a String\")\n}\n\nguard let variable = file.getVariable(name: \"MyData\") else {\n    fatalError(\"No variable named MyData available\")\n}\nguard let typedVariable = variable.asType(Int32.self) else {\n    fatalError(\"MyData is not a Int32 type\")\n}\nlet data2 = try typedVariable.read(offset: [1,1], count: [2,2])\n```\n\n3. Using groups, unlimited dimensions and compression\n\n```swift\nimport SwiftNetCDF\n\nlet file = try NetCDF.create(path: \"test.nc\", overwriteExisting: true)\n\n// Create new group. Analog the `getGroup(name: )` function can be used for existing groups\nlet subGroup = try file.createGroup(name: \"GROUP1\")\n\nlet dimLat = try subGroup.createDimension(name: \"LAT\", length: 10)\nlet dimLon = try subGroup.createDimension(name: \"LON\", length: 5, isUnlimited: true)\n\nvar lats = try subGroup.createVariable(name: \"LATITUDES\", type: Float.self, dimensions: [dimLat])\nvar lons = try subGroup.createVariable(name: \"LONGITUDES\", type: Float.self, dimensions: [dimLon])\n\ntry lats.write((0 ..\u003c 10).map(Float.init))\ntry lons.write((0 ..\u003c 5).map(Float.init))\n\n// `data` is of type `VariableGeneric\u003cFloat\u003e`. Define functions can be accessed via `data.variable`\nvar data = try subGroup.createVariable(name: \"DATA\", type: Float.self, dimensions: [dimLat, dimLon])\n\n// Enable compression, shuffle filter and chunking\ntry data.defineDeflate(enable: true, level: 6, shuffle: true)\ntry data.defineChunking(chunking: .chunked, chunks: [1, 5])\n\n/// Because the latitude dimension is unlimited, we can write more than the defined size\nlet array = (0 ..\u003c 1000).map(Float.init)\ntry data.write(array, offset: [0, 0], count: [10, 100])\n\n/// The check the new dimension count\nXCTAssertEqual(data.dimensionsFlat, [10, 100])\n\n// even more data at an offset\ntry data.write(array, offset: [0, 100], count: [10, 100])\n\nXCTAssertEqual(data.dimensionsFlat, [10, 200])\n```\n\n4. Discover the structure of a NetCDF file\n\n```swift\nimport SwiftNetCDF\n\nguard let file = try NetCDF.open(path: \"test.nc\", allowUpdate: false) else {\n    fatalError(\"File test.nc does not exist\")\n}\n\n/// Recursively print all groups\nfunc printGroup(_ group: Group) {\n    print(\"Group: \\(group.name)\")\n\n    for d in group.getDimensions() {\n        print(\"Dimension: \\(d.name) \\(d.length) \\(d.isUnlimited)\")\n    }\n\n    for v in group.getVariables() {\n        print(\"Variable: \\(v.name) \\(v.type.asExternalDataType()!)\")\n        for d in v.dimensions {\n            print(\"Variable dimension: \\(d.name) \\(d.length) \\(d.isUnlimited)\")\n        }\n    }\n\n    for a in try group.getAttributes() {\n        print(\"Attribute: \\(a.name) \\(a.length) \\(a.type.asExternalDataType()!)\")\n    }\n\n    for subgroup in group.getGroups() {\n        printGroup(subgroup)\n    }\n}\n\n// The root entry point of a NetCDF file is also a `Group`\nprintGroup(file)\n```\n\nOutput:\n```\nGroup: /\nGroup: GROUP1\nDimension: LAT 10 false\nDimension: LON 200 true\nVariable: LATITUDES float\nVariable dimension: LAT 10 false\nVariable: LONGITUDES float\nVariable dimension: LON 200 true\nVariable: DATA float\nVariable dimension: LAT 10 false\nVariable dimension: LON 200 true\n```\n\n## Features\n- Abstract Swift data types to NetCDF external types\n- Supported data types: `Float`, `Double`, `String`, `Int8`, `Int16`, `Int32`, `Int64`, `Int`, `UInt16`, `UInt32`, `UInt64` and `UInt`\n- Returns `nil` for missing files, variables, attributes or data-type mismatch\n- Exceptions are thrown for NetCDF library errors\n- Uses generics to ensure the correct type is being used\n- Thread safe. Access to the netCDF C API is serialized with thread locks\n\n## Limitations\n- User defined data types not yet implemented\n\n## Quick function reference\nSwiftNetCDF uses a simple data structures to organize access to NetCDF functions. The most important once are listed below.\n\n```swift\nstruct NetCDF {\n    static func create(path: String, overwriteExisting: Bool) -\u003e Group\n    static func open(path: String, allowUpdate: Bool) -\u003e Group?\n\n    /// Opens a NetCDF file from memory in read-only mode\n    static func open(memory: UnsafeRawBufferPointer)) -\u003e Group?\n}\n\nstruct Group {\n    let name: String\n\n    func getGroup(name: String) -\u003e Group?\n    func getGroups() -\u003e [Group]\n    func createGroup(name: String) -\u003e Group\n\n    func getDimensions() -\u003e [Dimension]\n    func createDimension(name: String, length: Int, isUnlimited: Bool = false) -\u003e Dimension\n\n    func getVariable(name: String) -\u003e Variable?\n    func getVariables() -\u003e [Variable]\n    func createVariable\u003cT\u003e(name: String, type: T.Type, dimensions: [Dimension]) -\u003e VariableGeneric\u003cT\u003e\n\n    func getAttribute(_ key: String) -\u003e Attribute?\n    func getAttributes() -\u003e [Attribute]\n    func setAttribute\u003cT\u003e(_ name: String, _ value: T)\n    func setAttribute\u003cT: NetcdfConvertible\u003e(_ name: String, _ value: [T])\n}\n\nstruct Variable {\n    let name: String\n\n    var dimensions: [Dimension]\n    var dimensionsFlat: [Int]\n\n    /// `Nil` in case of type mismatch\n    func asType\u003cT\u003e(_ of: T.Type) -\u003e VariableGeneric\u003cT\u003e?\n\n    func defineDeflate(enable: Bool, level: Int = 6, shuffle: Bool = false)\n    func defineChunking(chunking: VarId.Chunking, chunks: [Int])\n\n    // Same get/set attribute functions as a Group\n}\n\nstruct VariableGeneric\u003cT\u003e {\n    func read() -\u003e [T]\n    func read(offset: [Int], count: [Int]) -\u003e [T]\n    func read(offset: [Int], count: [Int], stride: [Int]) -\u003e [T]\n\n    func write(_ data: [T])\n    func write(_ data: [T], offset: [Int], count: [Int])\n    func write(_ data: [T], offset: [Int], count: [Int], stride: [Int])\n\n    // Same get/set attribute functions as a Group\n    // Same define functions as Variable\n}\n\nstruct Dimension {\n    let name: String\n    let length: Int\n    let isUnlimited: Bool\n}\n\nstruct Attribute {\n    let name: String\n    let length: Int\n\n    func read\u003cT: NetcdfConvertible\u003e() throws -\u003e T?\n    func read\u003cT: NetcdfConvertible\u003e() throws -\u003e [T]?\n}\n```\n\n\n## Contributing\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n\nPlease make sure to update tests as appropriate.\n\n## License\n[MIT](https://choosealicense.com/licenses/mit/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatrick-zippenfenig%2Fswiftnetcdf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpatrick-zippenfenig%2Fswiftnetcdf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatrick-zippenfenig%2Fswiftnetcdf/lists"}