diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8590806..d165af8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,29 +6,36 @@ permissions: pull-requests: write jobs: - # linting: - # name: Linting - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - name: Install dependencies - # run: | - # python -m pip install --upgrade pip - # pip install black ruff - # - name: Autoformat with black - # run: | - # black . - # - name: Lint with ruff - # run: | - # ruff check LoopProjectFile --fix - # - uses: stefanzweifel/git-auto-commit-action@v5 - # with: - # commit_message: "style: style fixes by ruff and autoformatting by black" - + linting: + name: Linting + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install black ruff + - name: Autoformat with black + run: | + black . + - name: Lint with ruff + run: | + ruff check . --fix + - name: Check for local changes + run: | + if [ -n "$(git status --porcelain)" ]; then + git config --global user.name "github-actions[bot]" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add . + git commit -m "style: style fixes by ruff and autoformatting by black" + fi + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "style: style fixes by ruff and autoformatting by black" pip-build-sdist: name: Build SDist - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 @@ -46,7 +53,7 @@ jobs: pip-test-sdist: name: Test sdist needs: pip-build-sdist - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Download sdist from artifacts uses: actions/download-artifact@v4 @@ -70,7 +77,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-24.04 - macos-latest - windows-latest @@ -98,13 +105,13 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-24.04 - macos-latest - windows-latest python-version: ["3.9", "3.10", "3.11", "3.12"] include: - - os: "ubuntu-latest" - artifact: loopprojectfile-wheels-ubuntu-latest + - os: "ubuntu-24.04" + artifact: loopprojectfile-wheels-ubuntu-24.04 - os: "macos-latest" artifact: loopprojectfile-wheels-macos-latest - os: "windows-latest" @@ -146,7 +153,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-24.04 - macos-latest - windows-latest python-version: ["3.9", "3.10", "3.11", "3.12"] @@ -195,7 +202,7 @@ jobs: release-please: needs: [pip-test-wheels, conda-build] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.ref == 'refs/heads/master' steps: - uses: actions/checkout@v4 diff --git a/LoopProjectFile/DataCollection.py b/LoopProjectFile/DataCollection.py index fe8d92f..695e55c 100644 --- a/LoopProjectFile/DataCollection.py +++ b/LoopProjectFile/DataCollection.py @@ -79,7 +79,8 @@ def CreateObservationGroup(dataCollectionGroup): obGroup.createDimension("foldObservationIndex", None) obGroup.createDimension("foliationObservationIndex", None) obGroup.createDimension("discontinuityObservationIndex", None) - obGroup.createDimension("stratigraphicObservationIndex", None) + obGroup.createDimension("stratigraphicObservationIndex", None) + faultObservationType_t = obGroup.createCompoundType( LoopProjectFile.faultObservationType, "FaultObservation" ) diff --git a/LoopProjectFile/Extents.py b/LoopProjectFile/Extents.py index 99893d4..a6dae05 100644 --- a/LoopProjectFile/Extents.py +++ b/LoopProjectFile/Extents.py @@ -1,6 +1,5 @@ # import netCDF4 - # Check extents of Loop Project File is valid def CheckExtentsValid(rootGroup, xyzGridSize, verbose=False): """ diff --git a/LoopProjectFile/ExtractedInformation.py b/LoopProjectFile/ExtractedInformation.py index 39a73d7..f689688 100644 --- a/LoopProjectFile/ExtractedInformation.py +++ b/LoopProjectFile/ExtractedInformation.py @@ -2,7 +2,6 @@ import LoopProjectFile import LoopProjectFile.LoopProjectFileUtils as LoopProjectFileUtils -# import numpy # Check Extracted Information valid if present @@ -51,6 +50,14 @@ def GetStratigraphicInformationGroup(rootGroup, verbose=False): ) +def GetStratigraphicThicknessGroup(rootGroup, verbose=False): + resp = GetExtractedInformationGroup(rootGroup, verbose) + if resp["errorFlag"]: + return resp + else: + return LoopProjectFileUtils.GetGroup(resp["value"], "StratigraphicThickness", verbose) + + def GetDrillholeDescriptionGroup(rootGroup, verbose=False): resp = GetExtractedInformationGroup(rootGroup, verbose) if resp["errorFlag"]: @@ -255,8 +262,12 @@ def GetDiscontinuityLog(root, indexList=[], indexRange=(0, 0), verbose=False): ) -# Set stratigraphic log -def SetStratigraphicLog(root, data, append=False, verbose=False): +def SetStratigraphicLog( + root, + data, + append=False, + verbose=False +): """ **SetStratigraphicLog** - Saves a list of strata in (formation, thickness) format into the netCDF Loop Project File @@ -267,6 +278,10 @@ def SetStratigraphicLog(root, data, append=False, verbose=False): The root group node of a Loop Project File data: list of (formation, thickness) The data to save + thickness_calculator_data: list of tuples + Labels for thickness calculators (e.g., [('Label1', 'Label2', ...)]) + thickness_calculator_active_flags: list of tuples + Flags for active thickness calculators (e.g., [('None', 'Active', ...)]) append: bool Flag of whether to append new data to existing log verbose: bool @@ -274,8 +289,8 @@ def SetStratigraphicLog(root, data, append=False, verbose=False): Returns ------- - dict {"errorFlag", "errorString"} - errorString exist and contains error message only when errorFlag is + dict {"errorFlag", "errorString"} + errorString exists and contains error message only when errorFlag is True """ @@ -302,11 +317,13 @@ def SetStratigraphicLog(root, data, append=False, verbose=False): zlib=True, complevel=9, ) + else: siGroup = resp["value"] if siGroup: stratigraphicLayersLocation = siGroup.variables["stratigraphicLayers"] + index = 0 if append: index = siGroup.dimensions["index"].size @@ -314,11 +331,14 @@ def SetStratigraphicLog(root, data, append=False, verbose=False): stratigraphicLayersLocation[index] = i index += 1 siGroup.setncattr("index_MaxValid", index) + + else: errStr = "(ERROR) Failed to create stratigraphic log group for strata setting" if verbose: print(errStr) response = {"errorFlag": True, "errorString": errStr} + return response @@ -330,16 +350,9 @@ def GetStratigraphicLog(root, indexList=[], indexRange=(0, 0), verbose=False): else: siGroup = resp["value"] data = [] - maxValidIndex = min( - siGroup.dimensions["index"].size, siGroup.getncattr("index_MaxValid") - ) + maxValidIndex = min(siGroup.dimensions["index"].size, siGroup.getncattr("index_MaxValid")) # Select all option - if ( - indexList == [] - and len(indexRange) == 2 - and indexRange[0] == 0 - and indexRange[1] == 0 - ): + if indexList == [] and len(indexRange) == 2 and indexRange[0] == 0 and indexRange[1] == 0: # Select all for i in range(0, maxValidIndex): data.append((siGroup.variables.get("stratigraphicLayers")[i])) @@ -351,11 +364,7 @@ def GetStratigraphicLog(root, indexList=[], indexRange=(0, 0), verbose=False): data.append((siGroup.variables.get("stratigraphicLayers")[i])) response["value"] = data # Select based on indices range option - elif ( - len(indexRange) == 2 - and indexRange[0] >= 0 - and indexRange[1] >= indexRange[0] - ): + elif len(indexRange) == 2 and indexRange[0] >= 0 and indexRange[1] >= indexRange[0]: for i in range(indexRange[0], indexRange[1]): if int(i) >= 0 and int(i) < maxValidIndex: data.append((siGroup.variables.get("stratigraphicLayers")[i])) @@ -368,6 +377,91 @@ def GetStratigraphicLog(root, indexList=[], indexRange=(0, 0), verbose=False): return response +def SetStratigraphicThicknesses(root, data, headers=None,ncols=None,append=False, verbose=False): + response = {"errorFlag": False} + resp = GetExtractedInformationGroup(root) + if resp["errorFlag"]: + # Create Extracted Information Group as it doesn't exist + eiGroup = root.createGroup("ExtractedInformation") + else: + eiGroup = resp["value"] + + resp = GetStratigraphicThicknessGroup(root) + if resp["errorFlag"]: + stGroup = eiGroup.createGroup("StratigraphicThickness") + stGroup.setncattr("index_MaxValid", -1) + stGroup.createDimension("index", None) + stratigraphicThicknessType_t = stGroup.createCompoundType( + LoopProjectFile.stratigraphicThicknessType, "stratigraphicThickness" + ) + stGroup.createVariable( + "stratigraphicThicknesses", + stratigraphicThicknessType_t, + ("index"), + zlib=True, + complevel=9, + ) + else: + stGroup = resp["value"] + + if stGroup: + stratigraphicThicknesses = stGroup.variables["stratigraphicThicknesses"] + if headers: + stGroup.setncattr("headers", headers) + if ncols: + stGroup.setncattr("ncols", ncols) + index = 0 + if append: + index = stGroup.dimensions["index"].size + for i in data: + stratigraphicThicknesses[index] = i + index += 1 + stGroup.setncattr("index_MaxValid", index) + else: + errStr = "(ERROR) Failed to create stratigraphic log group for strata setting" + if verbose: + print(errStr) + response = {"errorFlag": True, "errorString": errStr} + + return response + + +def GetStratigraphicThicknesses(root, indexList=[], indexRange=(0, 0), verbose=False): + response = {"errorFlag": False} + resp = GetStratigraphicThicknessGroup(root) + if resp["errorFlag"]: + response = resp + else: + siGroup = resp["value"] + data = [] + maxValidIndex = min(siGroup.dimensions["index"].size, siGroup.getncattr("index_MaxValid")) + # Select all option + response['attributes'] = {a:siGroup.getncattr(a) for a in siGroup.ncattrs()} + if indexList == [] and len(indexRange) == 2 and indexRange[0] == 0 and indexRange[1] == 0: + # Select all + for i in range(0, maxValidIndex): + data.append((siGroup.variables.get("stratigraphicThicknesses")[i])) + response["value"] = data + # Select based on list of indices option + elif indexList != []: + for i in indexList: + if int(i) >= 0 and int(i) < maxValidIndex: + data.append((siGroup.variables.get("stratigraphicThicknesses")[i])) + response["value"] = data + # Select based on indices range option + elif len(indexRange) == 2 and indexRange[0] >= 0 and indexRange[1] >= indexRange[0]: + for i in range(indexRange[0], indexRange[1]): + if int(i) >= 0 and int(i) < maxValidIndex: + data.append((siGroup.variables.get("stratigraphicThicknesses")[i])) + response["value"] = data + else: + errStr = "Non-implemented filter option" + if verbose: + print(errStr) + response = {"errorFlag": True, "errorString": errStr} + return response + + # Set drillhole log def SetDrillholeLog(root, data, append=False, verbose=False): """ diff --git a/LoopProjectFile/LoopProjectFile.py b/LoopProjectFile/LoopProjectFile.py index c54bef3..6796126 100644 --- a/LoopProjectFile/LoopProjectFile.py +++ b/LoopProjectFile/LoopProjectFile.py @@ -63,15 +63,6 @@ class EventRelationshipType(enum.IntEnum): FAULT_FAULT_ABUT = 3 FAULT_FAULT_OVERPRINT = 4 -class ThickenessCalculatorType(enum.IntEnum): - ALPHA = 0 - INTERPOLATED_STRUCTURE = 1 - STRUCTURAL_POINT = 2 - PLACEHOLDER_1 = 3 - PLACEHOLDER_2 = 4 - -# ### External Accessors ### # - # Create a basic loop project file if no file already exists def CreateBasic(filename): @@ -141,7 +132,7 @@ def OpenProjectFile(filename, readOnly=True, verbose=False): # Quick check to see if openable try: - with open(filename, 'rb') as f: + with open(filename, 'rb'): if (verbose): print(f"File {filename} opened successfully.", file=sys.stderr) except Exception as e: @@ -295,6 +286,12 @@ def Set(filename, element, **kwargs): response = ExtractedInformation.SetStratigraphicLog( root, append=True, **kwargs ) + elif element == "stratigraphicThicknesses": + response = ExtractedInformation.SetStratigraphicThicknesses(root, **kwargs) + elif element == "stratigraphicThicknessCalculatorLabels": + response = ExtractedInformation.SetStratigraphicThicknessCalculatorLabels(root, **kwargs) + + elif element == "faultLog": response = ExtractedInformation.SetFaultLog(root, **kwargs) elif element == "faultLogAppend": @@ -432,6 +429,10 @@ def Get(filename, element, **kwargs): response = DataCollection.GetDrillholeProperties(root, **kwargs) elif element == "stratigraphicLog": response = ExtractedInformation.GetStratigraphicLog(root, **kwargs) + elif element == "stratigraphicThicknesses": + response = ExtractedInformation.GetStratigraphicThicknesses(root, **kwargs) + elif element == "stratigraphicThicknessCalculatorLabels": + response = ExtractedInformation.GetStratigraphicThicknessCalculatorLabels(root, **kwargs) elif element == "faultLog": response = ExtractedInformation.GetFaultLog(root, **kwargs) elif element == "foldLog": @@ -499,6 +500,7 @@ def CheckValidElements(filename, verbose=False): "drillholeSurveys": False, "drillholeProperties": False, "stratigraphicLog": False, + "stratigraphicThicknesses": False, "faultLog": False, "foldLog": False, "foliationLog": False, @@ -739,9 +741,9 @@ def CheckFileValid(filename, verbose=False): ("group", "S120"), ("supergroup", "S120"), ("enabled", "u1"), - ("ThicknessMean", "