From 2bac1ac5a7b0a01f5e0247017dc8a3a2d9c1a32b Mon Sep 17 00:00:00 2001 From: Julian Giordani Date: Wed, 9 Apr 2025 10:52:36 +1000 Subject: [PATCH 1/7] Update xmlParser.py Add a flag to toggle if we force a final strata call in badlands (only during the Underworld coupling) or not. For some models this seems helpful, for others it doesn't. More testing is required. For now I am adding a flag and default setting it to false. --- badlands/badlands/forcing/xmlParser.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/badlands/badlands/forcing/xmlParser.py b/badlands/badlands/forcing/xmlParser.py index ac59b97..5a54d0b 100755 --- a/badlands/badlands/forcing/xmlParser.py +++ b/badlands/badlands/forcing/xmlParser.py @@ -42,6 +42,7 @@ def __init__(self, inputfile=None, makeUniqueOutputDir=True): self.Afactor = 1 self.nopit = 0 self.udw = 0 + self.udw_force_final_strata = 0 self.searef = None self.poro0 = 0.0 self.poroC = 0.47 @@ -290,6 +291,16 @@ def _get_XmL_Data(self): else: self.udw = 0 element = None + element = grid.find("udw_force_final_strata") + if element is not None: + self.udw_force_final_strata = int(element.text) + if self.udw_force_final_strata < 1: + self.udw_force_final_strata = 0 + else: + self.udw_force_final_strata = 1 + else: + self.udw_force_final_strata = 0 + element = None element = grid.find("searef") if element is not None: self.searef = eval(element.text) From b58cf0963df626edfe913578ff1b0f64d52a741d Mon Sep 17 00:00:00 2001 From: Julian Giordani Date: Wed, 9 Apr 2025 10:55:36 +1000 Subject: [PATCH 2/7] Update model.py Adding logic to build strata or not. --- badlands/badlands/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/badlands/badlands/model.py b/badlands/badlands/model.py index edd431d..e88208b 100755 --- a/badlands/badlands/model.py +++ b/badlands/badlands/model.py @@ -842,7 +842,7 @@ def run_to_time(self, tEnd, verbose=False): self.cumdiff += sub # if Underworld coupling is active, force a strata write at the end - if self.input.udw==1: + if self.input.udw==1 and self.input.udw_force_final_strata==1: purple = "\033[0;35m" endcol = "\033[00m" print(purple + "Stratal layering output to align with Underworld coupling" + endcol) From 4954b5fa0e0907874363339675eb62cf3b4237a5 Mon Sep 17 00:00:00 2001 From: Julian Giordani Date: Wed, 9 Apr 2025 11:12:18 +1000 Subject: [PATCH 3/7] Update meson.build updating version to 2.3.1 --- badlands/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/badlands/meson.build b/badlands/meson.build index 53afb0e..401cdca 100755 --- a/badlands/meson.build +++ b/badlands/meson.build @@ -1,6 +1,6 @@ project( 'badlands', 'fortran', 'c', - version:'2.3.0', + version:'2.3.1', license:'GPLv3', meson_version: '>=1.4.0', default_options : ['warning_level=2', 'python.install_env=auto']) From 5e076fdf614ec4376d0bade12217a2bdb5840f34 Mon Sep 17 00:00:00 2001 From: Julian Giordani Date: Wed, 9 Apr 2025 11:13:53 +1000 Subject: [PATCH 4/7] Update pyproject.toml Update version to 2.3.1 --- badlands/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/badlands/pyproject.toml b/badlands/pyproject.toml index 5ba122b..2ec9bb5 100644 --- a/badlands/pyproject.toml +++ b/badlands/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "mesonpy" [project] name = "badlands" -version = "2.3" +version = "2.3.1" authors = [ {name="Tristan Salles", email="tristan.salles@sydney.edu.au"}, ] From b6bd00e1cbe7a157325c78dae17d0ade207fc27a Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 20 Jun 2025 18:12:32 +1000 Subject: [PATCH 5/7] updates for tEnd, always override if use udw --- badlands/badlands/model.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/badlands/badlands/model.py b/badlands/badlands/model.py index e88208b..f6084f5 100755 --- a/badlands/badlands/model.py +++ b/badlands/badlands/model.py @@ -297,18 +297,20 @@ def run_to_time(self, tEnd, verbose=False): Warning: If specified end time (**tEnd**) is greater than the one defined in the XML input file priority - is given to the XML value. + is given to the XML value. If run from Underworld (or UWGeo) use tEnd not from XML file. """ assert hasattr( self, "recGrid" ), "DEM file has not been loaded. Configure one in your XML file or call the build_mesh function." - if tEnd > self.input.tEnd: - print( - "Specified end time is greater than the one used in the XML input file and has been adjusted!" - ) - tEnd = self.input.tEnd + # if run from Underworld alway use tEnd arg. + if self.input.udw == 0: + if tEnd > self.input.tEnd: + print( + "Specified end time is greater than the one used in the XML input file and has been adjusted!" + ) + tEnd = self.input.tEnd # Define non-flow related processes times if not self.simStarted: @@ -320,8 +322,8 @@ def run_to_time(self, tEnd, verbose=False): if self.input.laytime > 0: self.force.next_layer = self.input.tStart + self.input.laytime else: - self.force.next_layer = self.input.tEnd + 1000.0 - self.exitTime = self.input.tEnd + self.force.next_layer = tEnd + 1000.0 + self.exitTime = tEnd if self.input.flexure: self.force.next_flexure = self.input.tStart + self.input.ftime else: @@ -344,7 +346,7 @@ def run_to_time(self, tEnd, verbose=False): # Load precipitation rate if ( self.force.next_rain <= self.tNow - and self.force.next_rain < self.input.tEnd + and self.force.next_rain < tEnd ): if self.tNow == self.input.tStart: ref_elev = buildMesh.get_reference_elevation( @@ -365,7 +367,7 @@ def run_to_time(self, tEnd, verbose=False): # Vertical displacements if ( self.force.next_disp <= self.tNow - and self.force.next_disp < self.input.tEnd + and self.force.next_disp < tEnd ): ldisp = np.zeros(self.totPts, dtype=float) ldisp.fill(-1.0e6) @@ -381,7 +383,7 @@ def run_to_time(self, tEnd, verbose=False): # 3D displacements if ( self.force.next_disp <= self.tNow - and self.force.next_disp < self.input.tEnd + and self.force.next_disp < tEnd ): if self.input.laytime == 0: updateMesh = self.force.load_Disp_map( @@ -583,7 +585,7 @@ def run_to_time(self, tEnd, verbose=False): # Load carbonate growth rates for species 1 and 2 during a given growth event if ( self.force.next_carb <= self.tNow - and self.force.next_carb < self.input.tEnd + and self.force.next_carb < tEnd ): ( self.carbMaxGrowthSp1, @@ -842,7 +844,7 @@ def run_to_time(self, tEnd, verbose=False): self.cumdiff += sub # if Underworld coupling is active, force a strata write at the end - if self.input.udw==1 and self.input.udw_force_final_strata==1: + if self.input.udw==1: purple = "\033[0;35m" endcol = "\033[00m" print(purple + "Stratal layering output to align with Underworld coupling" + endcol) @@ -859,8 +861,9 @@ def run_to_time(self, tEnd, verbose=False): # Create checkpoint files and write HDF5 output if ( + #self.tNow == tEnd self.input.udw == 0 - or self.tNow == self.input.tEnd + or self.tNow == tEnd or self.tNow == self.force.next_display ): checkPoints.write_checkpoints( From 91f7e5f143bdbe82446198ea214a685aadf76bc2 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 3 Jul 2025 11:41:07 +1000 Subject: [PATCH 6/7] Using np.inf for switching off processes in time loop. * Previously `self.next_process = self.input.tEnd+1.0e5` was used. This was causing issues when UW coupling. This change should be fix it. * Change var names - easier to read --- badlands/badlands/model.py | 62 ++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/badlands/badlands/model.py b/badlands/badlands/model.py index f6084f5..13fb5e3 100755 --- a/badlands/badlands/model.py +++ b/badlands/badlands/model.py @@ -204,7 +204,7 @@ def _build_mesh(self, filename, verbose): if self.input.waveSed: self.force.next_wave = self.input.tStart + self.input.tWave else: - self.force.next_wave = self.input.tEnd + 1.0e5 + self.force.next_wave = np.inf if self.input.carb: @@ -213,7 +213,7 @@ def _build_mesh(self, filename, verbose): if self.carbTIN is not None: self.prop = np.zeros((self.totPts, self.carbTIN.nbSed)) else: - self.next_carbStep = self.input.tEnd + 1.0e5 + self.next_carbStep = np.inf self.prop = np.zeros((self.totPts, 1)) def _rebuild_mesh(self, verbose=False): @@ -304,13 +304,18 @@ def run_to_time(self, tEnd, verbose=False): self, "recGrid" ), "DEM file has not been loaded. Configure one in your XML file or call the build_mesh function." - # if run from Underworld alway use tEnd arg. - if self.input.udw == 0: - if tEnd > self.input.tEnd: - print( - "Specified end time is greater than the one used in the XML input file and has been adjusted!" - ) - tEnd = self.input.tEnd + # use the smallest tEnd, either passing or from the XML - when udw coupling is disabled + if (self.input.tEnd < tEnd) and (self.input.udw == 0): + print( + "Specified `tEnd` is greater than `tEnd` in the XML input file. Using the XML definition as it's smaller!" + ) + tEnd = self.input.tEnd + + # reference var within loop + tStart = self.input.tStart + ftime = self.input.ftime + tDisplay = self.input.tDisplay + laytime = self.input.laytime # Define non-flow related processes times if not self.simStarted: @@ -318,16 +323,15 @@ def run_to_time(self, tEnd, verbose=False): self.force.next_disp = self.force.T_disp[0, 0] self.force.next_carb = self.force.T_carb[0, 0] - self.force.next_display = self.input.tStart - if self.input.laytime > 0: - self.force.next_layer = self.input.tStart + self.input.laytime + self.force.next_display = tStart + if laytime > 0: + self.force.next_layer = tStart + laytime else: - self.force.next_layer = tEnd + 1000.0 - self.exitTime = tEnd + self.force.next_layer = np.inf if self.input.flexure: - self.force.next_flexure = self.input.tStart + self.input.ftime + self.force.next_flexure = tStart + ftime else: - self.force.next_flexure = self.exitTime + self.input.tDisplay + self.force.next_flexure = np.inf self.simStarted = True outStrata = 0 @@ -348,7 +352,7 @@ def run_to_time(self, tEnd, verbose=False): self.force.next_rain <= self.tNow and self.force.next_rain < tEnd ): - if self.tNow == self.input.tStart: + if self.tNow == tStart: ref_elev = buildMesh.get_reference_elevation( self.input, self.recGrid, self.elevation ) @@ -359,7 +363,7 @@ def run_to_time(self, tEnd, verbose=False): ) # Initialize waveFlux at tStart - # if self.tNow == self.input.tStart: + # if self.tNow == tStart: # self.force.initWaveFlux(self.inIDs) # Load tectonic grid @@ -385,7 +389,7 @@ def run_to_time(self, tEnd, verbose=False): self.force.next_disp <= self.tNow and self.force.next_disp < tEnd ): - if self.input.laytime == 0: + if laytime == 0: updateMesh = self.force.load_Disp_map( self.tNow, self.FVmesh.node_coords[:, :2], self.inIDs ) @@ -424,7 +428,7 @@ def run_to_time(self, tEnd, verbose=False): sload = None if ( self.input.udw == 1 - and self.tNow == self.input.tStart + and self.tNow == tStart and self.strata is not None ): if self.strata.oldload is None: @@ -436,7 +440,7 @@ def run_to_time(self, tEnd, verbose=False): self.strata.oldload = np.zeros( len(self.elevation), dtype=float ) - if self.input.laytime > 0 and self.strata.oldload is not None: + if laytime > 0 and self.strata.oldload is not None: sload = self.strata.oldload fstrat = 1 # Define erodibility map flags @@ -490,7 +494,7 @@ def run_to_time(self, tEnd, verbose=False): self.elevation += self.force.uDisp # Update the stratigraphic mesh - if self.input.laytime > 0 and self.strata is not None: + if laytime > 0 and self.strata is not None: self.strata.move_mesh(regdX, regdY, scum, verbose) # Compute isostatic flexure @@ -518,7 +522,7 @@ def run_to_time(self, tEnd, verbose=False): self.elevation += self.tinFlex self.cumflex += self.tinFlex # Update next flexure time - self.force.next_flexure += self.input.ftime + self.force.next_flexure += ftime print( " - Compute flexural isostasy %0.02f seconds" % (time.process_time() - flextime) @@ -657,7 +661,7 @@ def run_to_time(self, tEnd, verbose=False): # Update next stratal layer time if self.tNow >= self.force.next_layer: - self.force.next_layer += self.input.laytime + self.force.next_layer += laytime if self.straTIN is not None: self.straTIN.step += 1 if self.input.laststrat == True: @@ -698,7 +702,7 @@ def run_to_time(self, tEnd, verbose=False): # Create checkpoint files and write HDF5 output if self.tNow >= self.force.next_display: - if self.force.next_display > self.input.tStart: + if self.force.next_display > tStart: outStrata = 1 checkPoints.write_checkpoints( self.input, @@ -740,7 +744,7 @@ def run_to_time(self, tEnd, verbose=False): # Update next display time last_output = time.process_time() - self.force.next_display += self.input.tDisplay + self.force.next_display += tDisplay self.outputStep += 1 if self.carbTIN is not None: self.carbTIN.step += 1 @@ -821,7 +825,7 @@ def run_to_time(self, tEnd, verbose=False): self.elevation += self.tinFlex self.cumflex += self.tinFlex # Update next flexure time - self.force.next_flexure += self.input.ftime + self.force.next_flexure += ftime print( " - Compute flexural isostasy %0.02f seconds" % (time.process_time() - flextime) @@ -829,7 +833,7 @@ def run_to_time(self, tEnd, verbose=False): # Update next stratal layer time if self.tNow >= self.force.next_layer: - self.force.next_layer += self.input.laytime + self.force.next_layer += laytime if self.input.laststrat==True: self.write=1 # set parameter to call hdf5 stratal writer sub = self.strata.buildStrata( @@ -904,7 +908,7 @@ def run_to_time(self, tEnd, verbose=False): % (time.process_time() - meshtime) ) - self.force.next_display += self.input.tDisplay + self.force.next_display += tDisplay self.outputStep += 1 if self.straTIN is not None: self.straTIN.write_hdf5_stratigraphy(self.lGIDs, self.outputStep - 1) From 7c8d1e32d0f859a6697b622f06861249f36d8204 Mon Sep 17 00:00:00 2001 From: julian Date: Mon, 7 Jul 2025 10:41:28 +1000 Subject: [PATCH 7/7] Remove udw-force-final-strata xml tag, no longer needed --- badlands/badlands/forcing/xmlParser.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/badlands/badlands/forcing/xmlParser.py b/badlands/badlands/forcing/xmlParser.py index 5a54d0b..ac59b97 100755 --- a/badlands/badlands/forcing/xmlParser.py +++ b/badlands/badlands/forcing/xmlParser.py @@ -42,7 +42,6 @@ def __init__(self, inputfile=None, makeUniqueOutputDir=True): self.Afactor = 1 self.nopit = 0 self.udw = 0 - self.udw_force_final_strata = 0 self.searef = None self.poro0 = 0.0 self.poroC = 0.47 @@ -291,16 +290,6 @@ def _get_XmL_Data(self): else: self.udw = 0 element = None - element = grid.find("udw_force_final_strata") - if element is not None: - self.udw_force_final_strata = int(element.text) - if self.udw_force_final_strata < 1: - self.udw_force_final_strata = 0 - else: - self.udw_force_final_strata = 1 - else: - self.udw_force_final_strata = 0 - element = None element = grid.find("searef") if element is not None: self.searef = eval(element.text)