|
221 | 221 | "\n",
|
222 | 222 | "In the previous step we read the geometry and attributes of the branches from the shape file. This branch data will become the network input for our D-Flow FM model. \n",
|
223 | 223 | "\n",
|
224 |
| - "Since the model does not have a network yet, we need to create a new `Network` object and assign it to the model. A network may contain a 1D network, a 2D mesh and 1D2D links.\n", |
| 224 | + "Since the model does not have a network yet, we need to create a new network object and assign it to the model. A network may contain a 1D network, a 2D mesh and 1D2D links.\n", |
225 | 225 | "\n",
|
226 | 226 | "**Exercise 🧩**\n",
|
227 | 227 | "* Create a new network\n",
|
|
231 | 231 | " * For each branch, the name, geometry and computational grid points should be provided. \n",
|
232 | 232 | " * The computational points are not included in the data, we will need to generate those with a grid point distance as specified:\n",
|
233 | 233 | "\n",
|
234 |
| - " | **Branch name** | **dx [m]** |\n", |
235 |
| - " |-----------------|------------|\n", |
236 |
| - " | Channel_1D_1_A | 1000 |\n", |
237 |
| - " | Channel_1D_1_B | 1000 |\n", |
238 |
| - " | Channel_1D_1 | 500 |\n", |
| 234 | + "| **Branch name** | **dx [m]** |\n", |
| 235 | + "|-----------------|------------|\n", |
| 236 | + "| Channel_1D_1_A | 1000 |\n", |
| 237 | + "| Channel_1D_1_B | 1000 |\n", |
| 238 | + "| Channel_1D_1 | 500 |\n", |
239 | 239 | "\n",
|
240 |
| - "Hint 💡: The MDU file contains a [Geometry] section which has the `NetFile` reference, e.g.:\n", |
| 240 | + "Hint 💡: The MDU file contains a [Geometry] section which has the network file reference, e.g.:\n", |
241 | 241 | "\n",
|
242 | 242 | "```\n",
|
243 | 243 | "[Geometry]\n",
|
244 | 244 | "netFile = FlowFM_net.nc\n",
|
245 |
| - "bathymetryFile =\n", |
246 |
| - "dryPointsFile =\n", |
247 |
| - "structureFile = structures.ini\n", |
248 |
| - "iniFieldFile = initialFields.ini\n", |
249 | 245 | "...\n",
|
250 | 246 | "```\n",
|
251 | 247 | "\n",
|
|
254 | 250 | "* [NetworkModel](https://deltares.github.io/HYDROLIB-core/0.5.2/reference/net/#hydrolib.core.dflowfm.net.models.NetworkModel)\n",
|
255 | 251 | "* [Branch](https://deltares.github.io/HYDROLIB-core/0.5.2/reference/net/#hydrolib.core.dflowfm.net.models.Branch)\n",
|
256 | 252 | "* [Branch.generate_nodes()](https://deltares.github.io/HYDROLIB-core/0.5.2/reference/net/#hydrolib.core.dflowfm.net.models.Branch.generate_nodes)\n",
|
257 |
| - "* [Network.mesh1d_add_branch()](TODO)" |
| 253 | + "* `Network.mesh1d_add_branch()` (undocumented): Adds a branch to the 1D network.\n", |
| 254 | + " The function needs two arguments:\n", |
| 255 | + " 1. `Branch`: the branch to be added\n", |
| 256 | + " 2. `str`: The name of the branch that is added" |
258 | 257 | ]
|
259 | 258 | },
|
260 | 259 | {
|
|
279 | 278 | "# Assign geometry of the branches and generate the computational grid on top of the branches.\n",
|
280 | 279 | "for index, branch_data in branches_gdf.iterrows():\n",
|
281 | 280 | " xy = np.transpose(branch_data.geometry.xy) \n",
|
282 |
| - " branch_new = Branch(geometry=xy) \n", |
283 |
| - " branch_new.generate_nodes(mesh1d_edge_length=dx_per_branch[branch_data.Name])\n", |
284 |
| - " network.mesh1d_add_branch(branch_new, name=branch_data.Name)\n", |
| 281 | + " branch = Branch(geometry=xy) \n", |
| 282 | + " branch.generate_nodes(mesh1d_edge_length=dx_per_branch[branch_data.Name])\n", |
| 283 | + " network.mesh1d_add_branch(branch, name=branch_data.Name)\n", |
285 | 284 | "\n",
|
286 | 285 | "network._mesh1d._set_mesh1d()"
|
287 | 286 | ]
|
|
358 | 357 | "* Print the cross-section location data, to answer the following questions:\n",
|
359 | 358 | " * How many cross-section does the model contain in total, and how many does each branch have?\n",
|
360 | 359 | " * Do the cross-section have shared cross-section definitions? A shared cross-section definition is a definition used by more than one cross-section.\n",
|
361 |
| - "* Convert the CSV data (a pd.DataFrame) into a HYDROLIB-core `CrossSection`\n", |
362 |
| - "* Assign a file path to the cross section location file\n", |
| 360 | + "* Convert the CSV data (a pd.DataFrame) into HYDROLIB-core `CrossSection` objects\n", |
363 | 361 | "* Assign the cross section locations to the model\n",
|
364 | 362 | "\n",
|
365 | 363 | "Hint 💡: The MDU file contains a [Geometry] section which has the `crossDefFile` and `crossLocFile` reference, e.g.:\n",
|
|
372 | 370 | "```\n",
|
373 | 371 | "\n",
|
374 | 372 | "API references: \n",
|
375 |
| - "* [CrossLocModel](https://deltares.github.io/HYDROLIB-core/0.5.2/reference/crosssection/#hydrolib.core.dflowfm.crosssection.models.CrossLocModel)\n", |
376 |
| - "* [CrossSection](https://deltares.github.io/HYDROLIB-core/0.5.2/reference/crosssection/#hydrolib.core.dflowfm.crosssection.models.CrossSection)\n", |
377 | 373 | "* [pd.read_csv()](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html#pandas-read-csv)\n",
|
378 |
| - "* [pd.to_dict()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_dict.html#pandas-dataframe-to-dict)" |
| 374 | + "* [pd.to_dict()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_dict.html#pandas-dataframe-to-dict)\n", |
| 375 | + "* [CrossLocModel](https://deltares.github.io/HYDROLIB-core/0.5.2/reference/crosssection/#hydrolib.core.dflowfm.crosssection.models.CrossLocModel)\n", |
| 376 | + "* [CrossSection](https://deltares.github.io/HYDROLIB-core/0.5.2/reference/crosssection/#hydrolib.core.dflowfm.crosssection.models.CrossSection)" |
379 | 377 | ]
|
380 | 378 | },
|
381 | 379 | {
|
|
385 | 383 | "metadata": {},
|
386 | 384 | "outputs": [],
|
387 | 385 | "source": [
|
388 |
| - "cross_section_location_file = data_dir / 'cross_section_locations.csv'\n", |
389 |
| - "cross_section_locations_df = pd.read_csv(cross_section_location_file, index_col=False)\n", |
| 386 | + "cross_section_data_file = data_dir / 'cross_section_locations.csv'\n", |
| 387 | + "cross_section_df = pd.read_csv(cross_section_data_file, index_col=False)\n", |
390 | 388 | "\n",
|
391 |
| - "print(cross_section_locations_df)\n", |
| 389 | + "print(cross_section_df)\n", |
392 | 390 | "# Answers:\n",
|
393 | 391 | "# * There are 6 cross-sections in the model and each branch has two cross-sections \n",
|
394 | 392 | "# * There are no shared cross-section definitions; each cross-section has a unique definition ID.\n",
|
395 | 393 | "\n",
|
396 | 394 | "cross_loc_model = CrossLocModel()\n",
|
397 |
| - "cross_loc_model.filepath = 'crsloc.ini'\n", |
| 395 | + "model.geometry.crosslocfile = cross_loc_model\n", |
398 | 396 | "\n",
|
399 |
| - "cross_loc_model.crosssection = cross_section_locations_df.to_dict(\"records\")\n", |
400 |
| - "model.geometry.crosslocfile = cross_loc_model" |
| 397 | + "cross_loc_model.crosssection = cross_section_df.to_dict(\"records\")" |
401 | 398 | ]
|
402 | 399 | },
|
403 | 400 | {
|
|
407 | 404 | "source": [
|
408 | 405 | "### 6. Adding cross-section definitions\n",
|
409 | 406 | "\n",
|
410 |
| - "In the following exercise we will add the cross-section definitions to the D-Flow FM model. These belong to the cross-section we added in the previous step. These cross-sections all have YZ-profiles in order to define a natural shape of the river. \n", |
411 |
| - "\n", |
| 407 | + "In the following exercise we will add the cross-section definitions to the D-Flow FM model. These belong to the cross-sections we added in the previous step. These cross-sections all have YZ-profiles in order to define a natural shape of the river. \n", |
412 | 408 | "\n",
|
413 | 409 | "Please finish the code below.\n",
|
414 | 410 | "\n",
|
|
433 | 429 | "profiles_file = data_dir / '1D_YZ_CrossSections.xlsx'\n",
|
434 | 430 | "profile_excel_data = pd.read_excel(profiles_file, sheet_name=None)\n",
|
435 | 431 | "profile_names = list(profile_excel_data)\n",
|
436 |
| - "print(profile_names)\n", |
| 432 | + "print(f\"Profile names: {profile_names}\")\n", |
437 | 433 | "\n",
|
438 | 434 | "cross_def_model = CrossDefModel()\n",
|
439 |
| - "cross_def_model.filepath = 'crsdef.ini'\n", |
| 435 | + "model.geometry.crossdeffile = cross_def_model\n", |
440 | 436 | "\n",
|
441 | 437 | "# Properties for each YZ profile\n",
|
442 | 438 | "type_crs = 'yz'\n",
|
|
453 | 449 | " y_coords = profile_data.y.to_list()\n",
|
454 | 450 | " z_coords = profile_data.z.to_list()\n",
|
455 | 451 | "\n",
|
| 452 | + " # Define friction positions at begin and end of profile \n", |
456 | 453 | " friction_positions = [profile_data.y[0], profile_data.y[num_coords-1]]\n",
|
457 | 454 | "\n",
|
458 | 455 | " # Create an YZ profile\n",
|
|
468 | 465 | " frictionIds = friction_ids,\n",
|
469 | 466 | " frictionPositions=friction_positions)\n",
|
470 | 467 | " \n",
|
471 |
| - " cross_def_model.definition.append(cross_section)\n", |
472 |
| - "\n", |
473 |
| - "model.geometry.crossdeffile = cross_def_model\n" |
| 468 | + " cross_def_model.definition.append(cross_section)" |
474 | 469 | ]
|
475 | 470 | },
|
476 | 471 | {
|
|
502 | 497 | "\n",
|
503 | 498 | "channel_friction_model = FrictionModel()\n",
|
504 | 499 | "channel_friction_model.filepath = \"roughness-channels.ini\" # It is conventional to specify the file names as \"roughness-[friction ID].ini\"\n",
|
| 500 | + "model.geometry.frictfile = [channel_friction_model]\n", |
505 | 501 | "\n",
|
506 | 502 | "# Create global friction model and add it to frictionmodel\n",
|
507 | 503 | "channel_global_friction = FrictGlobal(frictionId=channel_friction_id,\n",
|
|
521 | 517 | " numLocations=1,\n",
|
522 | 518 | " functionType=function_type)\n",
|
523 | 519 | " \n",
|
524 |
| - " channel_friction_model.branch.append(friction_per_branch)\n", |
525 |
| - " \n", |
526 |
| - "model.geometry.frictfile = [channel_friction_model]" |
| 520 | + " channel_friction_model.branch.append(friction_per_branch)" |
527 | 521 | ]
|
528 | 522 | },
|
529 | 523 | {
|
530 | 524 | "cell_type": "markdown",
|
531 | 525 | "id": "51751aad",
|
532 | 526 | "metadata": {},
|
533 | 527 | "source": [
|
534 |
| - "We want to defined another global friction definition for the Canal del Dique. This friction model assumes Chezy as global friction type and a friction value of 45.\n", |
| 528 | + "We want to define another global friction definition for the Canal del Dique. This friction model assumes Chezy as global friction type and a friction value of 45.0.\n", |
| 529 | + "\n", |
| 530 | + "You can use the code above as an example.\n", |
535 | 531 | "\n",
|
536 | 532 | "**Exercise 🧩** \n",
|
537 | 533 | "* Create a new friction model for Canal del Dique\n",
|
|
551 | 547 | "metadata": {},
|
552 | 548 | "outputs": [],
|
553 | 549 | "source": [
|
554 |
| - "\n", |
555 | 550 | "dique_friction_id = 'dique'\n",
|
556 | 551 | "dique_global_type = FrictionType.chezy\n",
|
557 | 552 | "dique_global_value = 45.0\n",
|
558 | 553 | "\n",
|
559 | 554 | "dique_friction_model = FrictionModel()\n",
|
560 | 555 | "dique_friction_model.filepath = 'roughness-dique.ini'\n",
|
| 556 | + "model.geometry.frictfile.append(dique_friction_model)\n", |
561 | 557 | "\n",
|
562 | 558 | "dique_global_friction = FrictGlobal(frictionId=dique_friction_id,\n",
|
563 | 559 | " frictionType=dique_global_type,\n",
|
564 | 560 | " frictionValue=dique_global_value)\n",
|
565 |
| - "dique_friction_model.global_ = dique_global_friction\n", |
566 |
| - "\n", |
567 |
| - "model.geometry.frictfile.append(dique_friction_model)" |
| 561 | + "dique_friction_model.global_ = dique_global_friction" |
568 | 562 | ]
|
569 | 563 | },
|
570 | 564 | {
|
|
576 | 570 | "\n",
|
577 | 571 | "**Exercise 🧩** \n",
|
578 | 572 | "* Use the cross-section locations and definitions in the D-Flow FM model to find the cross-sections on the Channel_1D_1 branch\n",
|
579 |
| - "* Reassign the friction ID of the correct cross sections to one used for the Canal del Dique" |
| 573 | + "* Reassign the friction ID of the correct cross sections to the one used for the Canal del Dique" |
580 | 574 | ]
|
581 | 575 | },
|
582 | 576 | {
|
|
783 | 777 | "metadata": {},
|
784 | 778 | "outputs": [],
|
785 | 779 | "source": [
|
786 |
| - "\n", |
787 | 780 | "weir.crestlevel = 10.0\n",
|
788 | 781 | "weir.allowedflowdir = FlowDirection.positive"
|
789 | 782 | ]
|
|
839 | 832 | "source": [
|
840 | 833 | "### 12. Creating a 2D flexible mesh\n",
|
841 | 834 | "\n",
|
842 |
| - "Here, we demonstrate how to create a 2D mesh using `MeshKernel`.\n", |
843 |
| - "Note that the network and mesh functionality in HYDROLIB-core is still in development. \n", |
| 835 | + "Here, we demonstrate how to create a 2D mesh using MeshKernel.\n", |
| 836 | + "\n", |
| 837 | + "⚠️ *Network and mesh functionality in HYDROLIB-core is still in development.* \n", |
844 | 838 | "\n",
|
845 | 839 | "We use a shape file with the area of interest to define the extent of the new 2D mesh that is to be generated.\n",
|
846 | 840 | "First, a uniform rectilinear mesh with a grid cell size of 2500x2500m is generated.\n",
|
|
0 commit comments