diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..278c536 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +bin/* +*.o +build/* +*/build/* +*/*.xcodeproj/* !*.xcodeproj/project.pbxproj +*.xcodeproj +.svn + +.DS_Store +profile + +#Stuff for ignoring automake/autoconf files! +Makefile +*.m4 +config.* +configure +*.in +missing +install-sh +depcomp +stamp-h1 +*.cache/* +src/.* diff --git a/EF5/EF5.xcodeproj/project.pbxproj b/EF5/EF5.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c9ed108 --- /dev/null +++ b/EF5/EF5.xcodeproj/project.pbxproj @@ -0,0 +1,699 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + C47E4C9D1CAA986900DF6D73 /* ARS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C031CAA986900DF6D73 /* ARS.cpp */; }; + C47E4C9E1CAA986900DF6D73 /* AscGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C051CAA986900DF6D73 /* AscGrid.cpp */; }; + C47E4C9F1CAA986900DF6D73 /* BasicConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C071CAA986900DF6D73 /* BasicConfigSection.cpp */; }; + C47E4CA01CAA986900DF6D73 /* BasicGrids.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C091CAA986900DF6D73 /* BasicGrids.cpp */; }; + C47E4CA11CAA986900DF6D73 /* BasinConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C0B1CAA986900DF6D73 /* BasinConfigSection.cpp */; }; + C47E4CA31CAA986900DF6D73 /* BifGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C0E1CAA986900DF6D73 /* BifGrid.cpp */; }; + C47E4CA41CAA986900DF6D73 /* CaliParamConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C121CAA986900DF6D73 /* CaliParamConfigSection.cpp */; }; + C47E4CA61CAA986900DF6D73 /* Config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C151CAA986900DF6D73 /* Config.cpp */; }; + C47E4CA71CAA986900DF6D73 /* CRESTModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C181CAA986900DF6D73 /* CRESTModel.cpp */; }; + C47E4CA81CAA986900DF6D73 /* DamConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C1A1CAA986900DF6D73 /* DamConfigSection.cpp */; }; + C47E4CA91CAA986900DF6D73 /* DatedName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C1C1CAA986900DF6D73 /* DatedName.cpp */; }; + C47E4CAA1CAA986900DF6D73 /* DEMProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C1F1CAA986900DF6D73 /* DEMProcessor.cpp */; }; + C47E4CAB1CAA986900DF6D73 /* DistancePerTimeUnits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C211CAA986900DF6D73 /* DistancePerTimeUnits.cpp */; }; + C47E4CAC1CAA986900DF6D73 /* DistanceUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C231CAA986900DF6D73 /* DistanceUnit.cpp */; }; + C47E4CAD1CAA986900DF6D73 /* dream_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C251CAA986900DF6D73 /* dream_functions.cpp */; }; + C47E4CAE1CAA986900DF6D73 /* DREAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C281CAA986900DF6D73 /* DREAM.cpp */; }; + C47E4CAF1CAA986900DF6D73 /* EF5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C2A1CAA986900DF6D73 /* EF5.cpp */; }; + C47E4CB11CAA986900DF6D73 /* EnsTaskConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C2F1CAA986900DF6D73 /* EnsTaskConfigSection.cpp */; }; + C47E4CB21CAA986900DF6D73 /* ExecuteConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C311CAA986900DF6D73 /* ExecuteConfigSection.cpp */; }; + C47E4CB31CAA986900DF6D73 /* ExecutionController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C331CAA986900DF6D73 /* ExecutionController.cpp */; }; + C47E4CB41CAA986900DF6D73 /* GaugeConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C351CAA986900DF6D73 /* GaugeConfigSection.cpp */; }; + C47E4CB51CAA986900DF6D73 /* GaugeMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C371CAA986900DF6D73 /* GaugeMap.cpp */; }; + C47E4CB61CAA986900DF6D73 /* GeographicProjection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C391CAA986900DF6D73 /* GeographicProjection.cpp */; }; + C47E4CB71CAA986900DF6D73 /* GriddedOutput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C3C1CAA986900DF6D73 /* GriddedOutput.cpp */; }; + C47E4CB81CAA986900DF6D73 /* GridWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C3F1CAA986900DF6D73 /* GridWriter.cpp */; }; + C47E4CB91CAA986900DF6D73 /* GridWriterFull.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C411CAA986900DF6D73 /* GridWriterFull.cpp */; }; + C47E4CBA1CAA986900DF6D73 /* HPModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C431CAA986900DF6D73 /* HPModel.cpp */; }; + C47E4CBB1CAA986900DF6D73 /* HyMOD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C451CAA986900DF6D73 /* HyMOD.cpp */; }; + C47E4CBC1CAA986900DF6D73 /* InundationCaliParamConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C471CAA986900DF6D73 /* InundationCaliParamConfigSection.cpp */; }; + C47E4CBD1CAA986900DF6D73 /* InundationParamSetConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C491CAA986900DF6D73 /* InundationParamSetConfigSection.cpp */; }; + C47E4CBE1CAA986900DF6D73 /* KinematicRoute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C4B1CAA986900DF6D73 /* KinematicRoute.cpp */; }; + C47E4CC01CAA986900DF6D73 /* LAEAProjection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C4E1CAA986900DF6D73 /* LAEAProjection.cpp */; }; + C47E4CC11CAA986900DF6D73 /* LinearRoute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C501CAA986900DF6D73 /* LinearRoute.cpp */; }; + C47E4CC21CAA986900DF6D73 /* misc_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C531CAA986900DF6D73 /* misc_functions.cpp */; }; + C47E4CC31CAA986900DF6D73 /* Model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C551CAA986900DF6D73 /* Model.cpp */; }; + C47E4CC51CAA986900DF6D73 /* MRMSGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C5A1CAA986900DF6D73 /* MRMSGrid.cpp */; }; + C47E4CC71CAA986900DF6D73 /* ObjectiveFunc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C5D1CAA986900DF6D73 /* ObjectiveFunc.cpp */; }; + C47E4CC81CAA986900DF6D73 /* ParamSetConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C5F1CAA986900DF6D73 /* ParamSetConfigSection.cpp */; }; + C47E4CC91CAA986900DF6D73 /* PETConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C611CAA986900DF6D73 /* PETConfigSection.cpp */; }; + C47E4CCA1CAA986900DF6D73 /* PETReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C631CAA986900DF6D73 /* PETReader.cpp */; }; + C47E4CCB1CAA986900DF6D73 /* PETType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C651CAA986900DF6D73 /* PETType.cpp */; }; + C47E4CCC1CAA986900DF6D73 /* PrecipConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C671CAA986900DF6D73 /* PrecipConfigSection.cpp */; }; + C47E4CCD1CAA986900DF6D73 /* PrecipReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C691CAA986900DF6D73 /* PrecipReader.cpp */; }; + C47E4CCE1CAA986900DF6D73 /* PrecipType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C6B1CAA986900DF6D73 /* PrecipType.cpp */; }; + C47E4CCF1CAA986900DF6D73 /* RoutingCaliParamConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C6E1CAA986900DF6D73 /* RoutingCaliParamConfigSection.cpp */; }; + C47E4CD01CAA986900DF6D73 /* RoutingParamSetConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C701CAA986900DF6D73 /* RoutingParamSetConfigSection.cpp */; }; + C47E4CD11CAA986900DF6D73 /* RPSkewness.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C721CAA986900DF6D73 /* RPSkewness.cpp */; }; + C47E4CD21CAA986900DF6D73 /* SAC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C741CAA986900DF6D73 /* SAC.cpp */; }; + C47E4CD41CAA986900DF6D73 /* SimpleInundation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C781CAA986900DF6D73 /* SimpleInundation.cpp */; }; + C47E4CD51CAA986900DF6D73 /* Simulator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C7A1CAA986900DF6D73 /* Simulator.cpp */; }; + C47E4CD61CAA986900DF6D73 /* Snow17Model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C7C1CAA986900DF6D73 /* Snow17Model.cpp */; }; + C47E4CD71CAA986900DF6D73 /* SnowCaliParamConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C7E1CAA986900DF6D73 /* SnowCaliParamConfigSection.cpp */; }; + C47E4CD81CAA986900DF6D73 /* SnowParamSetConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C801CAA986900DF6D73 /* SnowParamSetConfigSection.cpp */; }; + C47E4CD91CAA986900DF6D73 /* TaskConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C821CAA986900DF6D73 /* TaskConfigSection.cpp */; }; + C47E4CDA1CAA986900DF6D73 /* TempConfigSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C841CAA986900DF6D73 /* TempConfigSection.cpp */; }; + C47E4CDB1CAA986900DF6D73 /* TempReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C861CAA986900DF6D73 /* TempReader.cpp */; }; + C47E4CDC1CAA986900DF6D73 /* TempType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C881CAA986900DF6D73 /* TempType.cpp */; }; + C47E4CDD1CAA986900DF6D73 /* TifGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C8A1CAA986900DF6D73 /* TifGrid.cpp */; }; + C47E4CDE1CAA986900DF6D73 /* TimeSeries.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C8C1CAA986900DF6D73 /* TimeSeries.cpp */; }; + C47E4CDF1CAA986900DF6D73 /* TimeUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C8E1CAA986900DF6D73 /* TimeUnit.cpp */; }; + C47E4CE01CAA986900DF6D73 /* TimeVar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C901CAA986900DF6D73 /* TimeVar.cpp */; }; + C47E4CE21CAA986900DF6D73 /* TRMMDGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C931CAA986900DF6D73 /* TRMMDGrid.cpp */; }; + C47E4CE41CAA986900DF6D73 /* TRMMRTGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C961CAA986900DF6D73 /* TRMMRTGrid.cpp */; }; + C47E4CE71CAA986900DF6D73 /* VCInundation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C47E4C9B1CAA986900DF6D73 /* VCInundation.cpp */; }; + C47E4CE91CAAAB7100DF6D73 /* UnixImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C47E4CE81CAAAB7100DF6D73 /* UnixImageIO.framework */; }; + C47E4CEB1CAAAB8000DF6D73 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C47E4CEA1CAAAB8000DF6D73 /* libz.tbd */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + C47E4BF71CAA984C00DF6D73 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + C47E4BF91CAA984C00DF6D73 /* EF5 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = EF5; sourceTree = BUILT_PRODUCTS_DIR; }; + C47E4C031CAA986900DF6D73 /* ARS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ARS.cpp; path = ../../src/ARS.cpp; sourceTree = "<group>"; }; + C47E4C041CAA986900DF6D73 /* ARS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARS.h; path = ../../src/ARS.h; sourceTree = "<group>"; }; + C47E4C051CAA986900DF6D73 /* AscGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AscGrid.cpp; path = ../../src/AscGrid.cpp; sourceTree = "<group>"; }; + C47E4C061CAA986900DF6D73 /* AscGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AscGrid.h; path = ../../src/AscGrid.h; sourceTree = "<group>"; }; + C47E4C071CAA986900DF6D73 /* BasicConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicConfigSection.cpp; path = ../../src/BasicConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C081CAA986900DF6D73 /* BasicConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasicConfigSection.h; path = ../../src/BasicConfigSection.h; sourceTree = "<group>"; }; + C47E4C091CAA986900DF6D73 /* BasicGrids.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicGrids.cpp; path = ../../src/BasicGrids.cpp; sourceTree = "<group>"; }; + C47E4C0A1CAA986900DF6D73 /* BasicGrids.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasicGrids.h; path = ../../src/BasicGrids.h; sourceTree = "<group>"; }; + C47E4C0B1CAA986900DF6D73 /* BasinConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasinConfigSection.cpp; path = ../../src/BasinConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C0C1CAA986900DF6D73 /* BasinConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasinConfigSection.h; path = ../../src/BasinConfigSection.h; sourceTree = "<group>"; }; + C47E4C0E1CAA986900DF6D73 /* BifGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BifGrid.cpp; path = ../../src/BifGrid.cpp; sourceTree = "<group>"; }; + C47E4C0F1CAA986900DF6D73 /* BifGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BifGrid.h; path = ../../src/BifGrid.h; sourceTree = "<group>"; }; + C47E4C101CAA986900DF6D73 /* BoundingBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BoundingBox.h; path = ../../src/BoundingBox.h; sourceTree = "<group>"; }; + C47E4C111CAA986900DF6D73 /* Calibrate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Calibrate.h; path = ../../src/Calibrate.h; sourceTree = "<group>"; }; + C47E4C121CAA986900DF6D73 /* CaliParamConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CaliParamConfigSection.cpp; path = ../../src/CaliParamConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C131CAA986900DF6D73 /* CaliParamConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CaliParamConfigSection.h; path = ../../src/CaliParamConfigSection.h; sourceTree = "<group>"; }; + C47E4C151CAA986900DF6D73 /* Config.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Config.cpp; path = ../../src/Config.cpp; sourceTree = "<group>"; }; + C47E4C161CAA986900DF6D73 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Config.h; path = ../../src/Config.h; sourceTree = "<group>"; }; + C47E4C171CAA986900DF6D73 /* ConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigSection.h; path = ../../src/ConfigSection.h; sourceTree = "<group>"; }; + C47E4C181CAA986900DF6D73 /* CRESTModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CRESTModel.cpp; path = ../../src/CRESTModel.cpp; sourceTree = "<group>"; }; + C47E4C191CAA986900DF6D73 /* CRESTModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CRESTModel.h; path = ../../src/CRESTModel.h; sourceTree = "<group>"; }; + C47E4C1A1CAA986900DF6D73 /* DamConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DamConfigSection.cpp; path = ../../src/DamConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C1B1CAA986900DF6D73 /* DamConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DamConfigSection.h; path = ../../src/DamConfigSection.h; sourceTree = "<group>"; }; + C47E4C1C1CAA986900DF6D73 /* DatedName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DatedName.cpp; path = ../../src/DatedName.cpp; sourceTree = "<group>"; }; + C47E4C1D1CAA986900DF6D73 /* DatedName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DatedName.h; path = ../../src/DatedName.h; sourceTree = "<group>"; }; + C47E4C1E1CAA986900DF6D73 /* Defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Defines.h; path = ../../src/Defines.h; sourceTree = "<group>"; }; + C47E4C1F1CAA986900DF6D73 /* DEMProcessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DEMProcessor.cpp; path = ../../src/DEMProcessor.cpp; sourceTree = "<group>"; }; + C47E4C201CAA986900DF6D73 /* DEMProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DEMProcessor.h; path = ../../src/DEMProcessor.h; sourceTree = "<group>"; }; + C47E4C211CAA986900DF6D73 /* DistancePerTimeUnits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DistancePerTimeUnits.cpp; path = ../../src/DistancePerTimeUnits.cpp; sourceTree = "<group>"; }; + C47E4C221CAA986900DF6D73 /* DistancePerTimeUnits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DistancePerTimeUnits.h; path = ../../src/DistancePerTimeUnits.h; sourceTree = "<group>"; }; + C47E4C231CAA986900DF6D73 /* DistanceUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DistanceUnit.cpp; path = ../../src/DistanceUnit.cpp; sourceTree = "<group>"; }; + C47E4C241CAA986900DF6D73 /* DistanceUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DistanceUnit.h; path = ../../src/DistanceUnit.h; sourceTree = "<group>"; }; + C47E4C251CAA986900DF6D73 /* dream_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dream_functions.cpp; path = ../../src/dream_functions.cpp; sourceTree = "<group>"; }; + C47E4C261CAA986900DF6D73 /* dream_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dream_functions.h; path = ../../src/dream_functions.h; sourceTree = "<group>"; }; + C47E4C271CAA986900DF6D73 /* dream_variables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dream_variables.h; path = ../../src/dream_variables.h; sourceTree = "<group>"; }; + C47E4C281CAA986900DF6D73 /* DREAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DREAM.cpp; path = ../../src/DREAM.cpp; sourceTree = "<group>"; }; + C47E4C291CAA986900DF6D73 /* DREAM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DREAM.h; path = ../../src/DREAM.h; sourceTree = "<group>"; }; + C47E4C2A1CAA986900DF6D73 /* EF5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = EF5.cpp; path = ../../src/EF5.cpp; sourceTree = "<group>"; }; + C47E4C2B1CAA986900DF6D73 /* EF5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EF5.h; path = ../../src/EF5.h; sourceTree = "<group>"; }; + C47E4C2F1CAA986900DF6D73 /* EnsTaskConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = EnsTaskConfigSection.cpp; path = ../../src/EnsTaskConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C301CAA986900DF6D73 /* EnsTaskConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EnsTaskConfigSection.h; path = ../../src/EnsTaskConfigSection.h; sourceTree = "<group>"; }; + C47E4C311CAA986900DF6D73 /* ExecuteConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExecuteConfigSection.cpp; path = ../../src/ExecuteConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C321CAA986900DF6D73 /* ExecuteConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecuteConfigSection.h; path = ../../src/ExecuteConfigSection.h; sourceTree = "<group>"; }; + C47E4C331CAA986900DF6D73 /* ExecutionController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExecutionController.cpp; path = ../../src/ExecutionController.cpp; sourceTree = "<group>"; }; + C47E4C341CAA986900DF6D73 /* ExecutionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionController.h; path = ../../src/ExecutionController.h; sourceTree = "<group>"; }; + C47E4C351CAA986900DF6D73 /* GaugeConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GaugeConfigSection.cpp; path = ../../src/GaugeConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C361CAA986900DF6D73 /* GaugeConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GaugeConfigSection.h; path = ../../src/GaugeConfigSection.h; sourceTree = "<group>"; }; + C47E4C371CAA986900DF6D73 /* GaugeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GaugeMap.cpp; path = ../../src/GaugeMap.cpp; sourceTree = "<group>"; }; + C47E4C381CAA986900DF6D73 /* GaugeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GaugeMap.h; path = ../../src/GaugeMap.h; sourceTree = "<group>"; }; + C47E4C391CAA986900DF6D73 /* GeographicProjection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GeographicProjection.cpp; path = ../../src/GeographicProjection.cpp; sourceTree = "<group>"; }; + C47E4C3A1CAA986900DF6D73 /* GeographicProjection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GeographicProjection.h; path = ../../src/GeographicProjection.h; sourceTree = "<group>"; }; + C47E4C3B1CAA986900DF6D73 /* Grid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Grid.h; path = ../../src/Grid.h; sourceTree = "<group>"; }; + C47E4C3C1CAA986900DF6D73 /* GriddedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GriddedOutput.cpp; path = ../../src/GriddedOutput.cpp; sourceTree = "<group>"; }; + C47E4C3D1CAA986900DF6D73 /* GriddedOutput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GriddedOutput.h; path = ../../src/GriddedOutput.h; sourceTree = "<group>"; }; + C47E4C3E1CAA986900DF6D73 /* GridNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GridNode.h; path = ../../src/GridNode.h; sourceTree = "<group>"; }; + C47E4C3F1CAA986900DF6D73 /* GridWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GridWriter.cpp; path = ../../src/GridWriter.cpp; sourceTree = "<group>"; }; + C47E4C401CAA986900DF6D73 /* GridWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GridWriter.h; path = ../../src/GridWriter.h; sourceTree = "<group>"; }; + C47E4C411CAA986900DF6D73 /* GridWriterFull.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GridWriterFull.cpp; path = ../../src/GridWriterFull.cpp; sourceTree = "<group>"; }; + C47E4C421CAA986900DF6D73 /* GridWriterFull.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GridWriterFull.h; path = ../../src/GridWriterFull.h; sourceTree = "<group>"; }; + C47E4C431CAA986900DF6D73 /* HPModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HPModel.cpp; path = ../../src/HPModel.cpp; sourceTree = "<group>"; }; + C47E4C441CAA986900DF6D73 /* HPModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HPModel.h; path = ../../src/HPModel.h; sourceTree = "<group>"; }; + C47E4C451CAA986900DF6D73 /* HyMOD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HyMOD.cpp; path = ../../src/HyMOD.cpp; sourceTree = "<group>"; }; + C47E4C461CAA986900DF6D73 /* HyMOD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HyMOD.h; path = ../../src/HyMOD.h; sourceTree = "<group>"; }; + C47E4C471CAA986900DF6D73 /* InundationCaliParamConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InundationCaliParamConfigSection.cpp; path = ../../src/InundationCaliParamConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C481CAA986900DF6D73 /* InundationCaliParamConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InundationCaliParamConfigSection.h; path = ../../src/InundationCaliParamConfigSection.h; sourceTree = "<group>"; }; + C47E4C491CAA986900DF6D73 /* InundationParamSetConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InundationParamSetConfigSection.cpp; path = ../../src/InundationParamSetConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C4A1CAA986900DF6D73 /* InundationParamSetConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InundationParamSetConfigSection.h; path = ../../src/InundationParamSetConfigSection.h; sourceTree = "<group>"; }; + C47E4C4B1CAA986900DF6D73 /* KinematicRoute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KinematicRoute.cpp; path = ../../src/KinematicRoute.cpp; sourceTree = "<group>"; }; + C47E4C4C1CAA986900DF6D73 /* KinematicRoute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KinematicRoute.h; path = ../../src/KinematicRoute.h; sourceTree = "<group>"; }; + C47E4C4E1CAA986900DF6D73 /* LAEAProjection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LAEAProjection.cpp; path = ../../src/LAEAProjection.cpp; sourceTree = "<group>"; }; + C47E4C4F1CAA986900DF6D73 /* LAEAProjection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LAEAProjection.h; path = ../../src/LAEAProjection.h; sourceTree = "<group>"; }; + C47E4C501CAA986900DF6D73 /* LinearRoute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LinearRoute.cpp; path = ../../src/LinearRoute.cpp; sourceTree = "<group>"; }; + C47E4C511CAA986900DF6D73 /* LinearRoute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LinearRoute.h; path = ../../src/LinearRoute.h; sourceTree = "<group>"; }; + C47E4C521CAA986900DF6D73 /* Messages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Messages.h; path = ../../src/Messages.h; sourceTree = "<group>"; }; + C47E4C531CAA986900DF6D73 /* misc_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = misc_functions.cpp; path = ../../src/misc_functions.cpp; sourceTree = "<group>"; }; + C47E4C541CAA986900DF6D73 /* misc_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = misc_functions.h; path = ../../src/misc_functions.h; sourceTree = "<group>"; }; + C47E4C551CAA986900DF6D73 /* Model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Model.cpp; path = ../../src/Model.cpp; sourceTree = "<group>"; }; + C47E4C561CAA986900DF6D73 /* Model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Model.h; path = ../../src/Model.h; sourceTree = "<group>"; }; + C47E4C571CAA986900DF6D73 /* ModelBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModelBase.h; path = ../../src/ModelBase.h; sourceTree = "<group>"; }; + C47E4C581CAA986900DF6D73 /* Models.tbl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Models.tbl; path = ../../src/Models.tbl; sourceTree = "<group>"; }; + C47E4C5A1CAA986900DF6D73 /* MRMSGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MRMSGrid.cpp; path = ../../src/MRMSGrid.cpp; sourceTree = "<group>"; }; + C47E4C5B1CAA986900DF6D73 /* MRMSGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MRMSGrid.h; path = ../../src/MRMSGrid.h; sourceTree = "<group>"; }; + C47E4C5D1CAA986900DF6D73 /* ObjectiveFunc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectiveFunc.cpp; path = ../../src/ObjectiveFunc.cpp; sourceTree = "<group>"; }; + C47E4C5E1CAA986900DF6D73 /* ObjectiveFunc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjectiveFunc.h; path = ../../src/ObjectiveFunc.h; sourceTree = "<group>"; }; + C47E4C5F1CAA986900DF6D73 /* ParamSetConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ParamSetConfigSection.cpp; path = ../../src/ParamSetConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C601CAA986900DF6D73 /* ParamSetConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ParamSetConfigSection.h; path = ../../src/ParamSetConfigSection.h; sourceTree = "<group>"; }; + C47E4C611CAA986900DF6D73 /* PETConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PETConfigSection.cpp; path = ../../src/PETConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C621CAA986900DF6D73 /* PETConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PETConfigSection.h; path = ../../src/PETConfigSection.h; sourceTree = "<group>"; }; + C47E4C631CAA986900DF6D73 /* PETReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PETReader.cpp; path = ../../src/PETReader.cpp; sourceTree = "<group>"; }; + C47E4C641CAA986900DF6D73 /* PETReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PETReader.h; path = ../../src/PETReader.h; sourceTree = "<group>"; }; + C47E4C651CAA986900DF6D73 /* PETType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PETType.cpp; path = ../../src/PETType.cpp; sourceTree = "<group>"; }; + C47E4C661CAA986900DF6D73 /* PETType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PETType.h; path = ../../src/PETType.h; sourceTree = "<group>"; }; + C47E4C671CAA986900DF6D73 /* PrecipConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrecipConfigSection.cpp; path = ../../src/PrecipConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C681CAA986900DF6D73 /* PrecipConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrecipConfigSection.h; path = ../../src/PrecipConfigSection.h; sourceTree = "<group>"; }; + C47E4C691CAA986900DF6D73 /* PrecipReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrecipReader.cpp; path = ../../src/PrecipReader.cpp; sourceTree = "<group>"; }; + C47E4C6A1CAA986900DF6D73 /* PrecipReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrecipReader.h; path = ../../src/PrecipReader.h; sourceTree = "<group>"; }; + C47E4C6B1CAA986900DF6D73 /* PrecipType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrecipType.cpp; path = ../../src/PrecipType.cpp; sourceTree = "<group>"; }; + C47E4C6C1CAA986900DF6D73 /* PrecipType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrecipType.h; path = ../../src/PrecipType.h; sourceTree = "<group>"; }; + C47E4C6D1CAA986900DF6D73 /* Projection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Projection.h; path = ../../src/Projection.h; sourceTree = "<group>"; }; + C47E4C6E1CAA986900DF6D73 /* RoutingCaliParamConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RoutingCaliParamConfigSection.cpp; path = ../../src/RoutingCaliParamConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C6F1CAA986900DF6D73 /* RoutingCaliParamConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RoutingCaliParamConfigSection.h; path = ../../src/RoutingCaliParamConfigSection.h; sourceTree = "<group>"; }; + C47E4C701CAA986900DF6D73 /* RoutingParamSetConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RoutingParamSetConfigSection.cpp; path = ../../src/RoutingParamSetConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C711CAA986900DF6D73 /* RoutingParamSetConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RoutingParamSetConfigSection.h; path = ../../src/RoutingParamSetConfigSection.h; sourceTree = "<group>"; }; + C47E4C721CAA986900DF6D73 /* RPSkewness.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RPSkewness.cpp; path = ../../src/RPSkewness.cpp; sourceTree = "<group>"; }; + C47E4C731CAA986900DF6D73 /* RPSkewness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RPSkewness.h; path = ../../src/RPSkewness.h; sourceTree = "<group>"; }; + C47E4C741CAA986900DF6D73 /* SAC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SAC.cpp; path = ../../src/SAC.cpp; sourceTree = "<group>"; }; + C47E4C751CAA986900DF6D73 /* SAC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SAC.h; path = ../../src/SAC.h; sourceTree = "<group>"; }; + C47E4C781CAA986900DF6D73 /* SimpleInundation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SimpleInundation.cpp; path = ../../src/SimpleInundation.cpp; sourceTree = "<group>"; }; + C47E4C791CAA986900DF6D73 /* SimpleInundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SimpleInundation.h; path = ../../src/SimpleInundation.h; sourceTree = "<group>"; }; + C47E4C7A1CAA986900DF6D73 /* Simulator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Simulator.cpp; path = ../../src/Simulator.cpp; sourceTree = "<group>"; }; + C47E4C7B1CAA986900DF6D73 /* Simulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Simulator.h; path = ../../src/Simulator.h; sourceTree = "<group>"; }; + C47E4C7C1CAA986900DF6D73 /* Snow17Model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Snow17Model.cpp; path = ../../src/Snow17Model.cpp; sourceTree = "<group>"; }; + C47E4C7D1CAA986900DF6D73 /* Snow17Model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Snow17Model.h; path = ../../src/Snow17Model.h; sourceTree = "<group>"; }; + C47E4C7E1CAA986900DF6D73 /* SnowCaliParamConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SnowCaliParamConfigSection.cpp; path = ../../src/SnowCaliParamConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C7F1CAA986900DF6D73 /* SnowCaliParamConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SnowCaliParamConfigSection.h; path = ../../src/SnowCaliParamConfigSection.h; sourceTree = "<group>"; }; + C47E4C801CAA986900DF6D73 /* SnowParamSetConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SnowParamSetConfigSection.cpp; path = ../../src/SnowParamSetConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C811CAA986900DF6D73 /* SnowParamSetConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SnowParamSetConfigSection.h; path = ../../src/SnowParamSetConfigSection.h; sourceTree = "<group>"; }; + C47E4C821CAA986900DF6D73 /* TaskConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TaskConfigSection.cpp; path = ../../src/TaskConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C831CAA986900DF6D73 /* TaskConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TaskConfigSection.h; path = ../../src/TaskConfigSection.h; sourceTree = "<group>"; }; + C47E4C841CAA986900DF6D73 /* TempConfigSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TempConfigSection.cpp; path = ../../src/TempConfigSection.cpp; sourceTree = "<group>"; }; + C47E4C851CAA986900DF6D73 /* TempConfigSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TempConfigSection.h; path = ../../src/TempConfigSection.h; sourceTree = "<group>"; }; + C47E4C861CAA986900DF6D73 /* TempReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TempReader.cpp; path = ../../src/TempReader.cpp; sourceTree = "<group>"; }; + C47E4C871CAA986900DF6D73 /* TempReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TempReader.h; path = ../../src/TempReader.h; sourceTree = "<group>"; }; + C47E4C881CAA986900DF6D73 /* TempType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TempType.cpp; path = ../../src/TempType.cpp; sourceTree = "<group>"; }; + C47E4C891CAA986900DF6D73 /* TempType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TempType.h; path = ../../src/TempType.h; sourceTree = "<group>"; }; + C47E4C8A1CAA986900DF6D73 /* TifGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TifGrid.cpp; path = ../../src/TifGrid.cpp; sourceTree = "<group>"; }; + C47E4C8B1CAA986900DF6D73 /* TifGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TifGrid.h; path = ../../src/TifGrid.h; sourceTree = "<group>"; }; + C47E4C8C1CAA986900DF6D73 /* TimeSeries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TimeSeries.cpp; path = ../../src/TimeSeries.cpp; sourceTree = "<group>"; }; + C47E4C8D1CAA986900DF6D73 /* TimeSeries.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeSeries.h; path = ../../src/TimeSeries.h; sourceTree = "<group>"; }; + C47E4C8E1CAA986900DF6D73 /* TimeUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TimeUnit.cpp; path = ../../src/TimeUnit.cpp; sourceTree = "<group>"; }; + C47E4C8F1CAA986900DF6D73 /* TimeUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeUnit.h; path = ../../src/TimeUnit.h; sourceTree = "<group>"; }; + C47E4C901CAA986900DF6D73 /* TimeVar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TimeVar.cpp; path = ../../src/TimeVar.cpp; sourceTree = "<group>"; }; + C47E4C911CAA986900DF6D73 /* TimeVar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeVar.h; path = ../../src/TimeVar.h; sourceTree = "<group>"; }; + C47E4C931CAA986900DF6D73 /* TRMMDGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TRMMDGrid.cpp; path = ../../src/TRMMDGrid.cpp; sourceTree = "<group>"; }; + C47E4C941CAA986900DF6D73 /* TRMMDGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TRMMDGrid.h; path = ../../src/TRMMDGrid.h; sourceTree = "<group>"; }; + C47E4C961CAA986900DF6D73 /* TRMMRTGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TRMMRTGrid.cpp; path = ../../src/TRMMRTGrid.cpp; sourceTree = "<group>"; }; + C47E4C971CAA986900DF6D73 /* TRMMRTGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TRMMRTGrid.h; path = ../../src/TRMMRTGrid.h; sourceTree = "<group>"; }; + C47E4C9B1CAA986900DF6D73 /* VCInundation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VCInundation.cpp; path = ../../src/VCInundation.cpp; sourceTree = "<group>"; }; + C47E4C9C1CAA986900DF6D73 /* VCInundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VCInundation.h; path = ../../src/VCInundation.h; sourceTree = "<group>"; }; + C47E4CE81CAAAB7100DF6D73 /* UnixImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UnixImageIO.framework; path = ../../../../../Library/Frameworks/UnixImageIO.framework; sourceTree = "<group>"; }; + C47E4CEA1CAAAB8000DF6D73 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + C47E4BF61CAA984C00DF6D73 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C47E4CEB1CAAAB8000DF6D73 /* libz.tbd in Frameworks */, + C47E4CE91CAAAB7100DF6D73 /* UnixImageIO.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + C47E4BF01CAA984C00DF6D73 = { + isa = PBXGroup; + children = ( + C47E4CEA1CAAAB8000DF6D73 /* libz.tbd */, + C47E4CE81CAAAB7100DF6D73 /* UnixImageIO.framework */, + C47E4BFB1CAA984C00DF6D73 /* EF5 */, + C47E4BFA1CAA984C00DF6D73 /* Products */, + ); + sourceTree = "<group>"; + }; + C47E4BFA1CAA984C00DF6D73 /* Products */ = { + isa = PBXGroup; + children = ( + C47E4BF91CAA984C00DF6D73 /* EF5 */, + ); + name = Products; + sourceTree = "<group>"; + }; + C47E4BFB1CAA984C00DF6D73 /* EF5 */ = { + isa = PBXGroup; + children = ( + C47E4D031CAD521F00DF6D73 /* Configs */, + C47E4D021CAD521700DF6D73 /* Grids */, + C47E4D011CAD51F900DF6D73 /* Calibration */, + C47E4D041CAD52DA00DF6D73 /* Models */, + C47E4C101CAA986900DF6D73 /* BoundingBox.h */, + C47E4C111CAA986900DF6D73 /* Calibrate.h */, + C47E4C1C1CAA986900DF6D73 /* DatedName.cpp */, + C47E4C1D1CAA986900DF6D73 /* DatedName.h */, + C47E4C1E1CAA986900DF6D73 /* Defines.h */, + C47E4C1F1CAA986900DF6D73 /* DEMProcessor.cpp */, + C47E4C201CAA986900DF6D73 /* DEMProcessor.h */, + C47E4C211CAA986900DF6D73 /* DistancePerTimeUnits.cpp */, + C47E4C221CAA986900DF6D73 /* DistancePerTimeUnits.h */, + C47E4C231CAA986900DF6D73 /* DistanceUnit.cpp */, + C47E4C241CAA986900DF6D73 /* DistanceUnit.h */, + C47E4C2A1CAA986900DF6D73 /* EF5.cpp */, + C47E4C2B1CAA986900DF6D73 /* EF5.h */, + C47E4C331CAA986900DF6D73 /* ExecutionController.cpp */, + C47E4C341CAA986900DF6D73 /* ExecutionController.h */, + C47E4C371CAA986900DF6D73 /* GaugeMap.cpp */, + C47E4C381CAA986900DF6D73 /* GaugeMap.h */, + C47E4C391CAA986900DF6D73 /* GeographicProjection.cpp */, + C47E4C3A1CAA986900DF6D73 /* GeographicProjection.h */, + C47E4C3B1CAA986900DF6D73 /* Grid.h */, + C47E4C3C1CAA986900DF6D73 /* GriddedOutput.cpp */, + C47E4C3D1CAA986900DF6D73 /* GriddedOutput.h */, + C47E4C3E1CAA986900DF6D73 /* GridNode.h */, + C47E4C3F1CAA986900DF6D73 /* GridWriter.cpp */, + C47E4C401CAA986900DF6D73 /* GridWriter.h */, + C47E4C411CAA986900DF6D73 /* GridWriterFull.cpp */, + C47E4C421CAA986900DF6D73 /* GridWriterFull.h */, + C47E4C4E1CAA986900DF6D73 /* LAEAProjection.cpp */, + C47E4C4F1CAA986900DF6D73 /* LAEAProjection.h */, + C47E4C521CAA986900DF6D73 /* Messages.h */, + C47E4C5D1CAA986900DF6D73 /* ObjectiveFunc.cpp */, + C47E4C5E1CAA986900DF6D73 /* ObjectiveFunc.h */, + C47E4C631CAA986900DF6D73 /* PETReader.cpp */, + C47E4C641CAA986900DF6D73 /* PETReader.h */, + C47E4C651CAA986900DF6D73 /* PETType.cpp */, + C47E4C661CAA986900DF6D73 /* PETType.h */, + C47E4C691CAA986900DF6D73 /* PrecipReader.cpp */, + C47E4C6A1CAA986900DF6D73 /* PrecipReader.h */, + C47E4C6B1CAA986900DF6D73 /* PrecipType.cpp */, + C47E4C6C1CAA986900DF6D73 /* PrecipType.h */, + C47E4C6D1CAA986900DF6D73 /* Projection.h */, + C47E4C721CAA986900DF6D73 /* RPSkewness.cpp */, + C47E4C731CAA986900DF6D73 /* RPSkewness.h */, + C47E4C7A1CAA986900DF6D73 /* Simulator.cpp */, + C47E4C7B1CAA986900DF6D73 /* Simulator.h */, + C47E4C861CAA986900DF6D73 /* TempReader.cpp */, + C47E4C871CAA986900DF6D73 /* TempReader.h */, + C47E4C881CAA986900DF6D73 /* TempType.cpp */, + C47E4C891CAA986900DF6D73 /* TempType.h */, + C47E4C8C1CAA986900DF6D73 /* TimeSeries.cpp */, + C47E4C8D1CAA986900DF6D73 /* TimeSeries.h */, + C47E4C8E1CAA986900DF6D73 /* TimeUnit.cpp */, + C47E4C8F1CAA986900DF6D73 /* TimeUnit.h */, + C47E4C901CAA986900DF6D73 /* TimeVar.cpp */, + C47E4C911CAA986900DF6D73 /* TimeVar.h */, + ); + path = EF5; + sourceTree = "<group>"; + }; + C47E4D011CAD51F900DF6D73 /* Calibration */ = { + isa = PBXGroup; + children = ( + C47E4C531CAA986900DF6D73 /* misc_functions.cpp */, + C47E4C541CAA986900DF6D73 /* misc_functions.h */, + C47E4C031CAA986900DF6D73 /* ARS.cpp */, + C47E4C041CAA986900DF6D73 /* ARS.h */, + C47E4C251CAA986900DF6D73 /* dream_functions.cpp */, + C47E4C261CAA986900DF6D73 /* dream_functions.h */, + C47E4C271CAA986900DF6D73 /* dream_variables.h */, + C47E4C281CAA986900DF6D73 /* DREAM.cpp */, + C47E4C291CAA986900DF6D73 /* DREAM.h */, + ); + name = Calibration; + sourceTree = "<group>"; + }; + C47E4D021CAD521700DF6D73 /* Grids */ = { + isa = PBXGroup; + children = ( + C47E4C051CAA986900DF6D73 /* AscGrid.cpp */, + C47E4C061CAA986900DF6D73 /* AscGrid.h */, + C47E4C091CAA986900DF6D73 /* BasicGrids.cpp */, + C47E4C0A1CAA986900DF6D73 /* BasicGrids.h */, + C47E4C0E1CAA986900DF6D73 /* BifGrid.cpp */, + C47E4C0F1CAA986900DF6D73 /* BifGrid.h */, + C47E4C5A1CAA986900DF6D73 /* MRMSGrid.cpp */, + C47E4C5B1CAA986900DF6D73 /* MRMSGrid.h */, + C47E4C8A1CAA986900DF6D73 /* TifGrid.cpp */, + C47E4C8B1CAA986900DF6D73 /* TifGrid.h */, + C47E4C931CAA986900DF6D73 /* TRMMDGrid.cpp */, + C47E4C941CAA986900DF6D73 /* TRMMDGrid.h */, + C47E4C961CAA986900DF6D73 /* TRMMRTGrid.cpp */, + C47E4C971CAA986900DF6D73 /* TRMMRTGrid.h */, + ); + name = Grids; + sourceTree = "<group>"; + }; + C47E4D031CAD521F00DF6D73 /* Configs */ = { + isa = PBXGroup; + children = ( + C47E4C2F1CAA986900DF6D73 /* EnsTaskConfigSection.cpp */, + C47E4C301CAA986900DF6D73 /* EnsTaskConfigSection.h */, + C47E4C311CAA986900DF6D73 /* ExecuteConfigSection.cpp */, + C47E4C321CAA986900DF6D73 /* ExecuteConfigSection.h */, + C47E4C0B1CAA986900DF6D73 /* BasinConfigSection.cpp */, + C47E4C0C1CAA986900DF6D73 /* BasinConfigSection.h */, + C47E4C121CAA986900DF6D73 /* CaliParamConfigSection.cpp */, + C47E4C131CAA986900DF6D73 /* CaliParamConfigSection.h */, + C47E4C1A1CAA986900DF6D73 /* DamConfigSection.cpp */, + C47E4C1B1CAA986900DF6D73 /* DamConfigSection.h */, + C47E4C151CAA986900DF6D73 /* Config.cpp */, + C47E4C161CAA986900DF6D73 /* Config.h */, + C47E4C171CAA986900DF6D73 /* ConfigSection.h */, + C47E4C071CAA986900DF6D73 /* BasicConfigSection.cpp */, + C47E4C081CAA986900DF6D73 /* BasicConfigSection.h */, + C47E4C351CAA986900DF6D73 /* GaugeConfigSection.cpp */, + C47E4C361CAA986900DF6D73 /* GaugeConfigSection.h */, + C47E4C471CAA986900DF6D73 /* InundationCaliParamConfigSection.cpp */, + C47E4C481CAA986900DF6D73 /* InundationCaliParamConfigSection.h */, + C47E4C491CAA986900DF6D73 /* InundationParamSetConfigSection.cpp */, + C47E4C4A1CAA986900DF6D73 /* InundationParamSetConfigSection.h */, + C47E4C6E1CAA986900DF6D73 /* RoutingCaliParamConfigSection.cpp */, + C47E4C6F1CAA986900DF6D73 /* RoutingCaliParamConfigSection.h */, + C47E4C701CAA986900DF6D73 /* RoutingParamSetConfigSection.cpp */, + C47E4C711CAA986900DF6D73 /* RoutingParamSetConfigSection.h */, + C47E4C5F1CAA986900DF6D73 /* ParamSetConfigSection.cpp */, + C47E4C601CAA986900DF6D73 /* ParamSetConfigSection.h */, + C47E4C611CAA986900DF6D73 /* PETConfigSection.cpp */, + C47E4C621CAA986900DF6D73 /* PETConfigSection.h */, + C47E4C7E1CAA986900DF6D73 /* SnowCaliParamConfigSection.cpp */, + C47E4C7F1CAA986900DF6D73 /* SnowCaliParamConfigSection.h */, + C47E4C801CAA986900DF6D73 /* SnowParamSetConfigSection.cpp */, + C47E4C811CAA986900DF6D73 /* SnowParamSetConfigSection.h */, + C47E4C821CAA986900DF6D73 /* TaskConfigSection.cpp */, + C47E4C831CAA986900DF6D73 /* TaskConfigSection.h */, + C47E4C841CAA986900DF6D73 /* TempConfigSection.cpp */, + C47E4C851CAA986900DF6D73 /* TempConfigSection.h */, + C47E4C671CAA986900DF6D73 /* PrecipConfigSection.cpp */, + C47E4C681CAA986900DF6D73 /* PrecipConfigSection.h */, + ); + name = Configs; + sourceTree = "<group>"; + }; + C47E4D041CAD52DA00DF6D73 /* Models */ = { + isa = PBXGroup; + children = ( + C47E4C181CAA986900DF6D73 /* CRESTModel.cpp */, + C47E4C191CAA986900DF6D73 /* CRESTModel.h */, + C47E4C431CAA986900DF6D73 /* HPModel.cpp */, + C47E4C441CAA986900DF6D73 /* HPModel.h */, + C47E4C451CAA986900DF6D73 /* HyMOD.cpp */, + C47E4C461CAA986900DF6D73 /* HyMOD.h */, + C47E4C4B1CAA986900DF6D73 /* KinematicRoute.cpp */, + C47E4C4C1CAA986900DF6D73 /* KinematicRoute.h */, + C47E4C501CAA986900DF6D73 /* LinearRoute.cpp */, + C47E4C511CAA986900DF6D73 /* LinearRoute.h */, + C47E4C551CAA986900DF6D73 /* Model.cpp */, + C47E4C561CAA986900DF6D73 /* Model.h */, + C47E4C571CAA986900DF6D73 /* ModelBase.h */, + C47E4C581CAA986900DF6D73 /* Models.tbl */, + C47E4C741CAA986900DF6D73 /* SAC.cpp */, + C47E4C751CAA986900DF6D73 /* SAC.h */, + C47E4C781CAA986900DF6D73 /* SimpleInundation.cpp */, + C47E4C791CAA986900DF6D73 /* SimpleInundation.h */, + C47E4C7C1CAA986900DF6D73 /* Snow17Model.cpp */, + C47E4C7D1CAA986900DF6D73 /* Snow17Model.h */, + C47E4C9B1CAA986900DF6D73 /* VCInundation.cpp */, + C47E4C9C1CAA986900DF6D73 /* VCInundation.h */, + ); + name = Models; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C47E4BF81CAA984C00DF6D73 /* EF5 */ = { + isa = PBXNativeTarget; + buildConfigurationList = C47E4C001CAA984C00DF6D73 /* Build configuration list for PBXNativeTarget "EF5" */; + buildPhases = ( + C47E4BF51CAA984C00DF6D73 /* Sources */, + C47E4BF61CAA984C00DF6D73 /* Frameworks */, + C47E4BF71CAA984C00DF6D73 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = EF5; + productName = EF5; + productReference = C47E4BF91CAA984C00DF6D73 /* EF5 */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C47E4BF11CAA984C00DF6D73 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "University of Oklahoma"; + TargetAttributes = { + C47E4BF81CAA984C00DF6D73 = { + CreatedOnToolsVersion = 7.2.1; + }; + }; + }; + buildConfigurationList = C47E4BF41CAA984C00DF6D73 /* Build configuration list for PBXProject "EF5" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C47E4BF01CAA984C00DF6D73; + productRefGroup = C47E4BFA1CAA984C00DF6D73 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C47E4BF81CAA984C00DF6D73 /* EF5 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + C47E4BF51CAA984C00DF6D73 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C47E4CD91CAA986900DF6D73 /* TaskConfigSection.cpp in Sources */, + C47E4CCD1CAA986900DF6D73 /* PrecipReader.cpp in Sources */, + C47E4CCB1CAA986900DF6D73 /* PETType.cpp in Sources */, + C47E4CA41CAA986900DF6D73 /* CaliParamConfigSection.cpp in Sources */, + C47E4CC21CAA986900DF6D73 /* misc_functions.cpp in Sources */, + C47E4CE21CAA986900DF6D73 /* TRMMDGrid.cpp in Sources */, + C47E4CE71CAA986900DF6D73 /* VCInundation.cpp in Sources */, + C47E4CBE1CAA986900DF6D73 /* KinematicRoute.cpp in Sources */, + C47E4CDE1CAA986900DF6D73 /* TimeSeries.cpp in Sources */, + C47E4CB61CAA986900DF6D73 /* GeographicProjection.cpp in Sources */, + C47E4CCC1CAA986900DF6D73 /* PrecipConfigSection.cpp in Sources */, + C47E4CC01CAA986900DF6D73 /* LAEAProjection.cpp in Sources */, + C47E4CB81CAA986900DF6D73 /* GridWriter.cpp in Sources */, + C47E4CAA1CAA986900DF6D73 /* DEMProcessor.cpp in Sources */, + C47E4C9F1CAA986900DF6D73 /* BasicConfigSection.cpp in Sources */, + C47E4CCA1CAA986900DF6D73 /* PETReader.cpp in Sources */, + C47E4CDD1CAA986900DF6D73 /* TifGrid.cpp in Sources */, + C47E4CAE1CAA986900DF6D73 /* DREAM.cpp in Sources */, + C47E4CCE1CAA986900DF6D73 /* PrecipType.cpp in Sources */, + C47E4CAF1CAA986900DF6D73 /* EF5.cpp in Sources */, + C47E4CA61CAA986900DF6D73 /* Config.cpp in Sources */, + C47E4CA71CAA986900DF6D73 /* CRESTModel.cpp in Sources */, + C47E4CA31CAA986900DF6D73 /* BifGrid.cpp in Sources */, + C47E4CE01CAA986900DF6D73 /* TimeVar.cpp in Sources */, + C47E4CCF1CAA986900DF6D73 /* RoutingCaliParamConfigSection.cpp in Sources */, + C47E4CA81CAA986900DF6D73 /* DamConfigSection.cpp in Sources */, + C47E4CD41CAA986900DF6D73 /* SimpleInundation.cpp in Sources */, + C47E4CD81CAA986900DF6D73 /* SnowParamSetConfigSection.cpp in Sources */, + C47E4CB41CAA986900DF6D73 /* GaugeConfigSection.cpp in Sources */, + C47E4CC91CAA986900DF6D73 /* PETConfigSection.cpp in Sources */, + C47E4CD21CAA986900DF6D73 /* SAC.cpp in Sources */, + C47E4CC71CAA986900DF6D73 /* ObjectiveFunc.cpp in Sources */, + C47E4CB91CAA986900DF6D73 /* GridWriterFull.cpp in Sources */, + C47E4CAD1CAA986900DF6D73 /* dream_functions.cpp in Sources */, + C47E4CAB1CAA986900DF6D73 /* DistancePerTimeUnits.cpp in Sources */, + C47E4CDA1CAA986900DF6D73 /* TempConfigSection.cpp in Sources */, + C47E4CA11CAA986900DF6D73 /* BasinConfigSection.cpp in Sources */, + C47E4CBC1CAA986900DF6D73 /* InundationCaliParamConfigSection.cpp in Sources */, + C47E4CD01CAA986900DF6D73 /* RoutingParamSetConfigSection.cpp in Sources */, + C47E4CD51CAA986900DF6D73 /* Simulator.cpp in Sources */, + C47E4CBD1CAA986900DF6D73 /* InundationParamSetConfigSection.cpp in Sources */, + C47E4CC11CAA986900DF6D73 /* LinearRoute.cpp in Sources */, + C47E4CD11CAA986900DF6D73 /* RPSkewness.cpp in Sources */, + C47E4C9D1CAA986900DF6D73 /* ARS.cpp in Sources */, + C47E4CC31CAA986900DF6D73 /* Model.cpp in Sources */, + C47E4CB71CAA986900DF6D73 /* GriddedOutput.cpp in Sources */, + C47E4CAC1CAA986900DF6D73 /* DistanceUnit.cpp in Sources */, + C47E4CB11CAA986900DF6D73 /* EnsTaskConfigSection.cpp in Sources */, + C47E4CC81CAA986900DF6D73 /* ParamSetConfigSection.cpp in Sources */, + C47E4CD61CAA986900DF6D73 /* Snow17Model.cpp in Sources */, + C47E4CB31CAA986900DF6D73 /* ExecutionController.cpp in Sources */, + C47E4CDC1CAA986900DF6D73 /* TempType.cpp in Sources */, + C47E4CA01CAA986900DF6D73 /* BasicGrids.cpp in Sources */, + C47E4CBA1CAA986900DF6D73 /* HPModel.cpp in Sources */, + C47E4CB21CAA986900DF6D73 /* ExecuteConfigSection.cpp in Sources */, + C47E4CDB1CAA986900DF6D73 /* TempReader.cpp in Sources */, + C47E4CD71CAA986900DF6D73 /* SnowCaliParamConfigSection.cpp in Sources */, + C47E4CB51CAA986900DF6D73 /* GaugeMap.cpp in Sources */, + C47E4CA91CAA986900DF6D73 /* DatedName.cpp in Sources */, + C47E4CE41CAA986900DF6D73 /* TRMMRTGrid.cpp in Sources */, + C47E4CC51CAA986900DF6D73 /* MRMSGrid.cpp in Sources */, + C47E4C9E1CAA986900DF6D73 /* AscGrid.cpp in Sources */, + C47E4CDF1CAA986900DF6D73 /* TimeUnit.cpp in Sources */, + C47E4CBB1CAA986900DF6D73 /* HyMOD.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C47E4BFE1CAA984C00DF6D73 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + C47E4BFF1CAA984C00DF6D73 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + C47E4C011CAA984C00DF6D73 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(LOCAL_LIBRARY_DIR)/Frameworks", + ); + HEADER_SEARCH_PATHS = /Library/Frameworks/UnixImageIO.framework/Headers; + OTHER_CFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + C47E4C021CAA984C00DF6D73 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(LOCAL_LIBRARY_DIR)/Frameworks", + ); + HEADER_SEARCH_PATHS = /Library/Frameworks/UnixImageIO.framework/Headers; + OTHER_CFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C47E4BF41CAA984C00DF6D73 /* Build configuration list for PBXProject "EF5" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C47E4BFE1CAA984C00DF6D73 /* Debug */, + C47E4BFF1CAA984C00DF6D73 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C47E4C001CAA984C00DF6D73 /* Build configuration list for PBXNativeTarget "EF5" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C47E4C011CAA984C00DF6D73 /* Debug */, + C47E4C021CAA984C00DF6D73 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = C47E4BF11CAA984C00DF6D73 /* Project object */; +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cf1ab25 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org> diff --git a/Makefile.am b/Makefile.am new file mode 100755 index 0000000..5651ebf --- /dev/null +++ b/Makefile.am @@ -0,0 +1,25 @@ +AUTOMAKE_OPTIONS = subdir-objects +ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} + +.rc.o: + $(WINDRES) src/ef5.rc -o $@ +%.o : %.rc + $(WINDRES) src/ef5.rc -o $@ + +bin_PROGRAMS = $(top_builddir)/bin/ef5 +unit_FILES = src/LAEAProjection.cpp src/GeographicProjection.cpp src/DistanceUnit.cpp src/TimeUnit.cpp src/DistancePerTimeUnits.cpp src/TimeVar.cpp +type_FILES = src/DatedName.cpp src/PETType.cpp src/PrecipType.cpp src/TempType.cpp src/GaugeMap.cpp +config_FILES = src/BasicConfigSection.cpp src/PrecipConfigSection.cpp src/PETConfigSection.cpp src/TempConfigSection.cpp src/GaugeConfigSection.cpp src/BasinConfigSection.cpp src/CaliParamConfigSection.cpp src/ParamSetConfigSection.cpp src/RoutingCaliParamConfigSection.cpp src/RoutingParamSetConfigSection.cpp src/TaskConfigSection.cpp src/EnsTaskConfigSection.cpp src/ExecuteConfigSection.cpp src/Config.cpp src/SnowCaliParamConfigSection.cpp src/SnowParamSetConfigSection.cpp src/InundationCaliParamConfigSection.cpp src/InundationParamSetConfigSection.cpp +input_FILES = src/RPSkewness.cpp src/TimeSeries.cpp src/PETReader.cpp src/PrecipReader.cpp src/TempReader.cpp src/TifGrid.cpp src/BifGrid.cpp src/AscGrid.cpp src/BasicGrids.cpp src/TRMMRTGrid.cpp src/MRMSGrid.cpp src/GridWriter.cpp src/GridWriterFull.cpp src/GriddedOutput.cpp +model_FILES = src/Model.cpp src/CRESTModel.cpp src/HyMOD.cpp src/SAC.cpp src/LinearRoute.cpp src/KinematicRoute.cpp src/ObjectiveFunc.cpp src/Simulator.cpp src/ARS.cpp src/DREAM.cpp src/dream_functions.cpp src/misc_functions.cpp src/Snow17Model.cpp src/HPModel.cpp src/SimpleInundation.cpp src/VCInundation.cpp +if WINDOWS +AM_CXXFLAGS= -Wall -mwindows ${OPENMP_CFLAGS} -fopenmp +__top_builddir__bin_ef5_SOURCES = $(unit_FILES) $(type_FILES) $(config_FILES) $(input_FILES) $(model_FILES) src/ExecutionController.cpp src/EF5Windows.cpp src/ef5.rc +else +AM_CXXFLAGS= -Wall -Werror ${OPENMP_CFLAGS} +__top_builddir__bin_ef5_SOURCES = $(unit_FILES) $(type_FILES) $(config_FILES) $(input_FILES) $(model_FILES) src/ExecutionController.cpp src/EF5.cpp src/DEMProcessor.cpp +endif +__top_builddir__bin_ef5_LDADD=-ltiff -lgeotiff -lz -lgomp + +EXTRA_PROGRAMS = $(top_builddir)/bin/kwtest +__top_builddir__bin_kwtest_SOURCES = $(unit_FILES) $(type_FILES) $(config_FILES) $(input_FILES) $(model_FILES) src/KWTest.cpp diff --git a/README.md b/README.md new file mode 100644 index 0000000..6da4314 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# Ensemble Framework For Flash Flood Forecasting (EF5) + +EF5 was created by the Hydrometeorology and Remote Sensing Laboratory at the University of Oklahoma. +The goal of EF5 is to have a framework for distributed hydrologic modeling that is user friendly, adaptable, expandable, all while being suitable for large scale (e.g. continental scale) modeling of flash floods with rapid forecast updates. Currently EF5 incorporates 3 water balance models including the Sacramento Soil Moisture Accouning Model (SAC-SMA), Coupled Routing and Excess Storage (CREST), and hydrophobic (HP). These water balance models can be coupled with either linear reservoir or kinematic wave routing. + +## Learn More + +EF5 has a homepage at [http://ef5.ou.edu](http://ef5.ou.edu). The training modules are found at [http://ef5.ou.edu/training/](http://ef5.ou.edu/training/) while the YouTube videos may be found at [https://www.youtube.com/channel/UCgoGJtdeqHgwoYIRhkgMwog](https://www.youtube.com/channel/UCgoGJtdeqHgwoYIRhkgMwog). The source code is found on GitHub at [https://github.com/HyDROSLab/EF5](https://github.com/HyDROSLab/EF5). + +See [manual.html](manual.html) for the EF5 operating manual which describes configuration options. + +## Compiling + +### Linux + +Clone the source code from GitHub. +1. autoreconf --force --install +2. ./configure + +This sets up the system, if you have a path where you would like to install the files then use ./configure --prefix=/path/to/someplace + +3. make + This compiles the EF5 application! + +### OS X + +Clone the source code from GitHub. Use the EF5 Xcode project found in the EF5 folder and compile the project. + +### Windows + +Currently cross-compiling from Linux is the recommended way of generating Windows binaries. + +Clone the source code from GitHub. + +1. autoreconf --force --install +2. For 32-bit Windows installations use ./configure --host=i686-w64-mingw32 + + For 64-bit Windows installations use ./configure --host=x86_64-w64-mingw32 + +3. make + + This compiles the EF5 application! + +## Contributors + +The following people are acknowledged for their contributions to the creation of EF5. + +Zac Flamig + +Humberto Vergara + +Race Clark + +JJ Gourley + +Yang Hong + diff --git a/compile_trmm_tools.csh b/compile_trmm_tools.csh new file mode 100755 index 0000000..4214fbd --- /dev/null +++ b/compile_trmm_tools.csh @@ -0,0 +1,9 @@ +#!/bin/csh + +g++ -O3 -o bin/TRMMRTClip src/TRMMRTClip.cpp src/TRMMRTGrid.cpp src/AscGrid.cpp -lz +g++ -O3 -o bin/TRMMDClip src/TRMMDClip.cpp src/TRMMDGrid.cpp src/AscGrid.cpp -lz +g++ -O3 -o bin/TRMMV6Clip src/TRMMV6Clip.cpp src/TRMMV6Grid.cpp src/AscGrid.cpp /usr/lib64/hdf/libmfhdf.a /usr/lib64/hdf/libdf.a -lz -ljpeg +g++ -O3 -o bin/BIFClip src/BIFClip.cpp src/BifGrid.cpp src/AscGrid.cpp +g++ -O3 -o bin/MRMSConvert src/MRMSConvert.cpp src/TifGrid.cpp src/MRMSGrid.cpp -lz -ltiff -lgeotiff +g++ -g -O3 -o bin/MRMSSum src/MRMSSum.cpp src/TifGrid.cpp src/MRMSGrid.cpp -lz -ltiff -lgeotiff +g++ -g -O3 -o bin/ComputeRP src/ComputeRP.cpp src/TifGrid.cpp -lz -ltiff -lgeotiff diff --git a/configure.ac b/configure.ac new file mode 100755 index 0000000..bc2efb5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,53 @@ +AC_INIT([Ensemble Framework For Flash Flood Forecasting], [0.1], [zac.flamig@noaa.gov], + [ef5], [http://hydro.ou.edu/]) +AC_PREREQ([2.62]) +AC_PROG_CXX +AC_OPENMP +AC_SUBST(OPENMP_CFLAGS) + +AC_CANONICAL_HOST +case $host_os in + *mingw*) + CFLAGS="$CFLAGS -static -static-libgcc -I/usr/local/include" + CXXFLAGS="$CXXFLAGS -static -static-libgcc -I/usr/local/include" + LDFLAGS="$LDFLAGS -static -static-libgcc -L/usr/local/lib" + WINDOWS=yes + AC_CHECK_TOOL(WINDRES, windres, no) + ;; + *) + ;; +esac +AM_CONDITIONAL(WINDOWS, test x$WINDOWS = xyes) +#AC_CHECK_LIB([z], [gzread], [],[ +# echo "z library is required for this EF5" +# exit -1]) +#AC_CHECK_LIB([tiff], [TIFFReadScanline], [],[ +# echo "Tiff library is required for this EF5" +# exit -1]) +#AC_CHECK_LIB([geotiff], [GTIFNew], [],[ +# echo "GeoTiff library is required for this EF5" +# exit -1]) +#if test x$WINDOWS != xyes; then +#AC_CHECK_LIB([gomp], [omp_get_wtime], [],[ +# echo "gomp library is required for this EF5" +# exit -1]) +#fi; +LIBS=-lz -ltiff -lgeotiff +AC_CHECK_HEADERS(xtiffio.h) +AC_CHECK_HEADERS(geotiff/xtiffio.h) +AC_CHECK_HEADERS(libgeotiff/xtiffio.h) +if test x"$ac_cv_header_geotiff_xtiffio_h" = x"yes"; then + CPPFLAGS="-I/usr/include/geotiff"; +else + if test x"$ac_cv_header_libgeotiff_xtiffio_h" = x"yes"; then + CPPFLAGS="-I/usr/include/libgeotiff"; + else + if test x"$ac_cv_header_xtiffio_h" != x"yes"; then + AC_MSG_ERROR([xtiffio.h header not found]); + fi; + fi; +fi; +AM_INIT_AUTOMAKE([1.9.6 -Wall -Werror no-define foreign]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/ef5.ico b/ef5.ico new file mode 100644 index 0000000..1a40b57 Binary files /dev/null and b/ef5.ico differ diff --git a/manual.html b/manual.html new file mode 100755 index 0000000..3814b35 --- /dev/null +++ b/manual.html @@ -0,0 +1,572 @@ +<html> + <head> + <title>EF5 User Manual</title> + <style type="text/css"> + body { font-face: Georgia; width: 90%; } + #header { text-align: center; } + #toc ol ol li { list-style-type: lower-alpha; } + #contents li { font-size: 16pt; font-weight: bold; } + #contents ol ol li {font-size: 13pt; font-weight: bold; list-style-type: lower-alpha; } + pre {background-color: #dadada; padding: 7px; margin-bottom: 0; width: 700px; border: 1px solid #aaaaaa; } + .prec {font-style: italic; font-size: smaller; margin-top: 0;} + .pree { background-color: #daffda; padding: 7px; margin-bottom: 0; width: 400px; } + .valuec {background-color: #dadaff; padding: 3px; margin: 0; width: 95%;} + .namec {font-weight: bold; font-style: italic; } + </style> + </head> + <body> + <div id="header"> + <h1>Ensemble Framework For Flash Flood Forecasting (EF5)</h1> + Version 1.0 (July, 2016) + </div> + <div id="toc"> + <h3>Table of Contents</h3> + <ol> + <li><a href="#about">About EF5</a></li> + <li>Hydrologic Water Balance Models + <ol> + <li><a href="#crest">CREST</a></li> + <li><a href="#sac">SAC-SMA</a></li> + <li><a href="#hp">HP</a></li> + </ol> + </li> + <li>Routing Models + <ol> + <li><a href="#lr">Linear Reservior</a></li> + <li><a href="#kw">Kinematic Wave</a></li> + </ol> + </li> + <li>Snow Melt Models + <ol> + <li><a href="#snow17">Snow-17</a></li> + </ol> + </li> + <li>Inundation Models + <ol> + <li><a href="#si">Simple Inundation</a></li> + </ol> + </li> + <li><a href="#compile">Compiling EF5</a></li> + <li><a href="#config">Configuration File</a> + <ol> + <li><a href="#basic">Basic Information</a></li> + <li><a href="#precip">Precipitation Information</a></li> + <li><a href="#pet">Potentional Evapotranspiration Information</a></li> + <li><a href="#gauge">Gauge Locations</a></li> + <li><a href="#basin">Basins</a></li> + <li><a href="#param">Parameter Sets</a> + <ol> + <li><a href="#paramcrest">CREST</a></li> + <li><a href="#paramsac">SAC-SMA</a></li> + <li><a href="#paramhp">HP</a></li> + <li><a href="#paramlr">Linear Reservoir</a></li> + <li><a href="#paramkw">Kinematic Wave</a></li> + <li><a href="#paramsnow17">Snow-17</a></li> + <li><a href="#paramsi">Simple Inundation</a></li> + </ol> + </li> + <li><a href="#task">Tasks</a></li> + <li><a href="#execute">Execute Block</a></li> + </ol> + </li> + <li><a href="#run">Running EF5</a></li> + <li><a href="#cali">Calibrating the Models</a></li> + <li>Appendix + <ol> + <li><a href="#cconfig">Complete Sample Configuration File</a></li> + </ol> + </li> + </ol> + </div> + <div id="contents"> + <ol> + <li><a name="about">About EF5</a></li> + <p>EF5 is designed to facilitate creation of ensemble forecasts for flash flood prediction. As such it will incorporate multi-model support while maintaining a single set of input data. Currently the only supported model is the Coupled Routing and Excess Storage (CREST) hydrologic model. Additionally, EF5 was designed with utilization of parallel computing in mind. Presently portions of CREST are optimized to take advantage of multi-core computing through the use of OpenMP.</p> + <li>Hydrologic Water Balance Models</li> + <ol> + <li><a name="crest">CREST</a></li> + <p>The Coupled Routing and Excess STorage (CREST) distributed hydrological model is a hybrid modeling strategy that was recently developed by the University of Oklahoma (<a href="http://hydro.ou.edu">http://hydro.ou.edu</a>) and NASA SERVIR Project Team (<a href="http://www.servir.net">www.servir.net</a>). CREST simulates the spatiotemporal variation of water and energy fluxes and storages on a regular grid with the grid cell resolution being user-defined, thereby enabling global- and regional-scale applications. The scalability of CREST simulations is accomplished through sub-grid scale representation of soil moisture storage capacity (using a variable infiltration curve) and runoff generation processes (using linear reservoirs). The CREST model was initially developed to provide online global flood predictions with relatively coarse resolution, but it is also applicable at small scales, such as single basins. The CREST Model can be forced by gridded potential evapotranspiration and precipitation datasets such as, satellite-based precipitation estimates, gridded rain gauge observations, remote sensing platforms such as weather radar, and quantitative precipitation forecasts from numerical weather prediction models. The representation of the primary water fluxes such as infiltration and routing are closely related to the spatially variable land surface characteristics (i.e., vegetation, soil type, and topography). The runoff generation component and routing scheme are coupled, thus providing realistic interactions between atmospheric, land surface, and subsurface water. + <br /><br />More detailed information about CREST can be found in the following publication:<br /><a href="http://dx.doi.org/10.1080/02626667.2010.543087">Wang, J., Y. Hong, L. Li, J. J. Gourley, S. I. Khan, K. K. Yilmaz, R. F. Adler, F. S. Policelli, S. Habib, D. Irwin, A. S. Limaye, T. Korme, and L. Okello, 2011: The coupled routing and excess storage (CREST) distributed hydrological model. <em>Hydrol. Sci. Journal</em>, <strong>56</strong>, 84-98, doi: 10.1080/02626667.2010.543087.</a> + </p> + <li><a name="sac">SAC-SMA</a></li> + <p>The Sacramento Soil Moisture Accounting (SAC-SMA) Model was developed by the U.S. National Weather Service with the goal of parameterizing soil moisture characteristics in a fashion that would 1) logically distribute applied moisture in various depths and energy states in the soil 2) have rational percolation characteristics 3) allow an effective simulation of streamflow. + <br /><br />More detailed information about SAC-SMA can be found online at <a href="http://www.nws.noaa.gov/oh/hrl/nwsrfs/users_manual/part2/_pdf/23sacsma.pdf"> U.S. NWS SAC-SMA algorithm description</a></p> + <li><a name="hp">HP</a></li> + <p>The Hydrophobic (HP) water balance model features an entirely impervious surface where all rainfall is transformed into surface runoff.</p> + </ol> + <li>Routing Models</li> + <ol> + <li><a name="lr">Linear Reservoir</a></li> + <p> + The linear reservoir routing is adapted from the CREST implementation. There are two reservoirs, one for overland/surface runoff and one for subsurface runoff. + </p> + <li><a name="kw">Kinematic Wave</a></li> + <p>Kinematic wave routing is a simplified approximation of the Barré de Saint-Venant equations developed in 1871. Kinematic wave routing assumes the gravity force and friction force are equal and cancel while neglecting the acceleration terms.</p> + </ol> + <li>Snow Melt Models</li> + <ol> + <li><a name="snow17">Snow-17</a></li> + <p>Snow-17 is a temperature index based snow melt module widely used by the U.S. NWS. + </p> + </ol> + <li>Inundation Models</li> + <ol> + <li><a name="si">Simple Inundation</a></li> + <p> + </p> + </ol> + <li><a name="compile">Compiling EF5</a></li> + <p> + EF5 makes use of the TIFF and GEOTIFF libraries for use as a raster format. You can obtain binaries or source code and compilation documentation from: </br> + Compiling EF5 can be accomplished in 3 steps:<br /> + 1. This step is only needed if you are a developer and are adding files to the Makefile.am <pre class="pree">autoreconf --force --install</pre><br /> + 2. This sets up the system, if you have a path where you would like to install the files then use ./configure --prefix=/path/to/someplace <pre class="pree">./configure</pre><br /> + 3. This step actually compiles ef5 and generates the binary <pre class="pree">make CXXFLAGS="-O3 -fopenmp"</pre><br /> + Upon successful compilation there will be a binary called "ef5" in the "bin" directory. + </p> + <li><a name="config">Configuration File</a></li> + <p>The configuration file specifies all of the user changeable settings for EF5. Information in this file controls the input forcings, output options, run methods, etc.</p> + <p>In general the configuration file is case <strong>insensitive</strong>. The only exception is file paths when working on case sensitive file systems such as those typically found in Linux/Unix.</p> + <p>The configuration file supports three different styles of comments. The three styles are bash (#), C (/**/) and C++ (//).</p> +<pre>#All variables/names/etc with the exception of +#file paths are case insensitive +//Multiple comment types are supported +/* + Including multi-line C-style comments + */ +</pre><p class="prec">Example of the different comment styles.</p> + <ol> + <li><a name="basic">Basic Information</a></li> + <p>The basic section of the configuration file specifies the digital elevation model (DEM), drainage direction map (DDM), and flow accumulation map (FAM) files.<br /> +<pre> +[Basic] +DEM=/EF5Demo/FF/basic/DEM.asc +DDM=/EF5Demo/FF/basic/DDM.asc +FAM=/EF5Demo/FF/basic/FAM.asc +PROJ=laea +ESRIDDM=true +SELFFAM=true +</pre><p class="prec">Example Basic Block</p> +<span class="namec">DEM:</span> Specifies the location and file name of the DEM grid in ESRI ascii or float32 geotiff format.<br /> +<span class="namec">DDM:</span> Specifies the location and file name of the DDM grid in ESRI ascii or float32 geotiff format.<br /> +<span class="namec">FAM:</span> Specifies the location and file name of the FAM grid in ESRI ascii or float32 geotiff format.<br /> +<span class="namec">PROJ:</span> Specifies the projection that the model will be expecting for input files. Possible values are:<br /> +<pre class="valuec"> +<em>Geographic</em>: Standard geographic projection +<em>LAEA</em>: Lambert Azimuthal Equal Area projection with the standard parallel at 45.0 and the central meridian at -100.0. +</pre> +<span class="namec">ESRIDDM:</span> Specifies if the DDM is in ESRI format or TauDEM format. Possible values are:<br /> +<pre class="valuec"> +<em>true</em>: The directions in the DDM are specified as <table border="1" width="85px" style="text-align: center"><tr><td>32</td><td>64</td><td>128</td></tr><tr><td>16</td><td> </td><td>1</td></tr><tr><td>8</td><td>4</td><td>2</td></tr></table> +<em>false</em>: The directions in the DDM are specified as <table border="1" width="85px" style="text-align: center"><tr><td>4</td><td>3</td><td>2</td></tr><tr><td>5</td><td> </td><td>1</td></tr><tr><td>6</td><td>7</td><td>8</td></tr></table> +</pre> +<span class="namec">SELFFAM:</span> Specifies if the flow accumulation map includes the current grid cell in the flow count. Possible values are:<br /> +<pre class="valuec"> +<em>true</em>: The lowest flow accumulation value for any grid cell will be 1. +<em>false</em>: The lowest flow accumulation value for any grid cell will be 0. +</pre> +</p> + <li><a name="precip">Precipitation Information</a></li> + <p>The precipitation forcing section specifies the information necessary to adequately describe the precipitation product that the model will ingest.<br /> +<pre> +[PrecipForcing Q2Precip] +TYPE=BIF +UNIT=mm/h +FREQ=5u +LOC=/EF5Demo/FF/precip +NAME=Q2_YYYYMMDDHHUU.bif +</pre><p class="prec">Example PrecipForcing Block</p> +<span class="namec">PrecipForcing Block Name:</span> This specifies in the name of the precipitation forcing block as it will be referred to later in the configuration file. In the above example the block name is "Q2Precip". <br /> +<span class="namec">TYPE:</span> Specifies the file type of the precipitation. Possible type values are:<br /> +<pre class="valuec"> +<em>ASC</em>: An ESRI ASCII grid. +<em>BIF</em>: A binary file version of an ESRI ASCII grid. +<em>TIF</em>: A float32 geotiff grid. +<em>TRMMRT</em>: TRMM Multisatellite Precipitation Analysis realtime binary grid. Can be gzip compressed. +<em>TRMMV7</em>: TRMM Multisatellite Precipitation Analysis 3B42V7 HDF5 grid. +<em>MRMS</em>: Multi-Radar Multi-Sensor binary grid. +</pre> +<span class="namec">UNIT:</span> Specifies the units of the precipitation in the file. Supported length units are meters (m), centimeters (cm) and millimeters (mm). Supported time units are year (y), month (m), day (d), hour (h), minute (u) and second (s). Modifiers in front of the time portion are also supported. For example if your precipitation forcing file has units of millimeters per three hours then your "UNIT" line would appear as "UNIT=mm/3h".<br /> +<span class="namec">FREQ:</span> Specifies the frequency at which precipitation files should be ingested by the model. Supported time units are year (y), month (m), day (d), hour (h), minute (u) and second (s).<br /> +<span class="namec">LOC:</span> Specifies the directory location of the precipitation forcing files.<br /> +<span class="namec">NAME:</span> Specifies the naming convention of the precipitation forcing files. These files can (and should) contain valid time dates. The name can be of any format. YYYY will be replaced with the year, MM replaced with the month, DD replaced with the day, HH replaced with the hour, UU replaced with the minute and SS replaced with the second.<br /><br /> + <li><a name="pet">Potential Evapotranspiration (PET) Information</a></li> + <p>The potential evapotranspiration forcing section specifies the information necessary to adequately describe the PET product that the model will ingest.<br /></p> +<pre> +[PETForcing PET] +TYPE=BIF +UNIT=mm/h +FREQ=m +LOC=/EF5Demo/FF/pet +NAME=PET_MM.bif +</pre><p class="prec">Example PETForcing Block</p> +<span class="namec">PETForcing Block Name:</span> This specifies in the name of the PET forcing block as it will be referred to later in the configuration file. In the above example the block name is "PET". <br /> +<span class="namec">TYPE:</span> Specifies the file type of the PET. Possible type values are:<br /> +<pre class="valuec"> +<em>ASC</em>: An ESRI ASCII grid. +<em>BIF</em>: A binary version of an ESRI ASCII grid. +<em>TIF</em>: A float32 geotiff grid. +</pre> +<span class="namec">UNIT:</span> Specifies the units of the PET in the file. Supported length units are meters (m), centimeters (cm) and millimeters (mm). Support +ed time units are year (y), month (m), day (d), hour (h), minute (u) and second (s). Modifiers in front of the time portion are also supported. For example if your PET forcing file has units of millimeters per three hours then your "UNIT" line would appear as "UNIT=mm/3h".<br /> PET data may also be given as temperate data in degrees Celsius with unit "C". The temperature data is converted into PET.<br /> +<span class="namec">FREQ:</span> Specifies the frequency at which PET files should be ingested by the model. Supported time units are year (y), month (m), day (d +), hour (h), minute (u) and second (s).<br /> +<span class="namec">LOC:</span> Specifies the directory location of the PET forcing files.<br /> +<span class="namec">NAME:</span> Specifies the naming convention of the PET forcing files. These files can (and should) contain valid time dates. The name can be + of any format. YYYY will be replaced with the year, MM replaced with the month, DD replaced with the day, HH replaced with the hour, UU replaced with the minute and SS replaced with the second.<br /><br /> + <li><a name="gauge">Gauge Locations</a></li> + <p>These blocks specify the location of the gauges to the model. This is useful if you want time series output at a point and also to specify parameters. Basins are treated as collections of gauges with the outlet gauge being the independent gauge and all other gauges inside a basin being dependent gauges.</p> +<pre>[Gauge OKC] +LON=-97.01 +LAT=35.68 +OBS=/EF5Demo/obs/okc.csv +BASINAREA=341.88 +OUTPUTTS=TRUE + +[Gauge AR] +LON=-93.62 +LAT=34.37 +</pre><p class="prec">Example Gauge Location Blocks</p> +<span class="namec">Gauge Location Block Name:</span> This specifies in the name of the gauge location block as it will be referred to later in the configuration file. In the above example the block names are "OKC" and "AR". <br /> +<span class="namec">LON:</span> This is the longitude of the gauge in an unprojected coordinate system. EF5 will reproject the gauge point into the appropriate coordinate system.<br /> +<span class="namec">LAT:</span> This is the latitude of the gauge in an unprojected coordinate system. EF5 will reproject the gauge point into the appropriate coordinate system.<br /> +<span class="namec">CELLX:</span> <em>(optional)</em> This is the x-coordinate of the gauge in the basic file, used in place of LAT-LON.<br /> +<span class="namec">CELLY:</span> <em>(optional)</em> This is the y-coordinate of the gauge in the basic file, used in place of LAT-LON.<br /> +<span class="namec">OBS:</span> <em>(optional)</em> This is a file containing a time series specifying the observed values at the gauge. This is only used during model calibration.<br /> +<span class="namec">BASINAREA:</span> <em>(optional)</em> Observed contributing basin area for this gauge in km<sup>2</sup>. EF5 will search nearby grid cells to match flow accumulations as closely as possible.<br /> +<span class="namec">OUPUTTS:</span> <em>(optional)</em> Output a time series file for this gauge. Possible values are TRUE, YES, FALSE and NO. Default value is YES<br /> +<span class="namec">WANTDA:</span> <em>(optional)</em> If we are doing data assimilation, do we want it done for this gauge? Possible values are TRUE, YES, FALSE and NO. Default value is YES<br /> +<span class="namec">WANTCO:</span> <em>(optional)</em> Do we want this gauge included in the combined output file? Possible values are TRUE, YES, FALSE and NO. Default value is NO<br /><br /> + + <li><a name="basin">Basins</a></li> + <p>These blocks do not represent actual physical basins but rather a collection of specified gauge locations that may or may not form a single independent basin.</p> +<pre>[Basin FF] +GAUGE=OKC +GAUGE=AR +</pre><p class="prec">Example Basin Block</p> +<span class="namec">Basin Block Name:</span> This specifies in the name of the basin block as it will be referred to later in the configuration file. In the above example the block name is "FF". <br /> +<span class="namec">GAUGE:</span> This is the name of the gauge location block to include as part of this basin.<br /><br /> + + <li><a name="param">Parameter Sets</a></li> + <p>These blocks control the distributed model parameter settings. Parameters are specified per gauge and propogated upstream. Therefore each independent gauge must have a parameter set specified. Gridded parameters can be specified using the parameter name combined with "_grid" with a value specifying the grid file. When gridded parameters and uniform parameters are specified the uniform parameters act as scalar multipliers on the gridded parameter values.</p> + <ol> + <li><a name="paramcrest">CREST Parameter Set</a></li> +<pre> +[CrestParamSet ABRFC] +wm_grid=/hydros/zflamig/EF5_Jess/params/crest_params/wm_usa.tif +im_grid=/hydros/zflamig/EF5_Jess/params/crest_params/im_usa.tif +fc_grid=/hydros/zflamig/EF5_Jess/params/crest_params/ksat_usa.tif +b_grid=/hydros/zflamig/EF5_Jess/params/crest_params/b_usa.tif +gauge=03455500 +wm=1.00 +b=1.0 +im=0.01 +ke=1.0 +fc=1.00 +iwu=50.0 +</pre><p class="prec">Example CrestParamSet Block</p> + <span class="namec">GAUGE:</span> This is the name of the gauge location block for which the parameters that follow it will be applied.<br /> + <span class="namec">WM:</span> The maximum soil water capacity (depth integrated pore space) of the soil layer. (mm)<br /> + <span class="namec">B:</span> The exponent of the variable infiltration curve.<br /> + <span class="namec">IM:</span> The impervious area ratio. (% between 0 and 100)<br /> + <span class="namec">KE:</span> The multiplier to convert between input PET and local actual ET.<br /> + <span class="namec">FC:</span> The soil saturated hydraulic conductivity (Ksat). (mm hr<sup>-1</sup>) <br /> + <span class="namec">IWU:</span> The initial value of soil water. This is a percentage of the WM. (% between 0 and 100)<br /><br /> + + <li><a name="paramsac">SAC-SMA Parameter Set</a></li> + <pre> +[SacParamSet ABRFC] +UZTWM_grid=/data/FLASH/v2/sac_params/uztwm_usa.tif +UZFWM_grid=/data/FLASH/v2/sac_params/uzfwm_usa.tif +UZK_grid=/data/FLASH/v2/sac_params/uzk_usa.tif +ZPERC_grid=/data/FLASH/v2/sac_params/zperc_usa.tif +REXP_grid=/data/FLASH/v2/sac_params/rexp_usa.tif +LZTWM_grid=/data/FLASH/v2/sac_params/lztwm_usa.tif +LZFSM_grid=/data/FLASH/v2/sac_params/lzfsm_usa.tif +LZFPM_grid=/data/FLASH/v2/sac_params/lzfpm_usa.tif +LZSK_grid=/data/FLASH/v2/sac_params/lzsk_usa.tif +LZPK_grid=/data/FLASH/v2/sac_params/lzpk_usa.tif +PFREE_grid=/data/FLASH/v2/sac_params/pfree_usa.tif +gauge=01055000 +UZTWM=1.0 +UZFWM=1.0 +UZK=1.0 +PCTIM=0.101 +ADIMP=0.10 +RIVA=1.001 +ZPERC=1.0 +REXP=1.0 +LZTWM=1.0 +LZFSM=1.0 +LZFPM=1.0 +LZSK=1.0 +LZPK=1.0 +PFREE=1.0 +SIDE=0.0 +RSERV=0.3 +ADIMC=1.0 +UZTWC=0.55 +UZFWC=0.14 +LZTWC=0.56 +LZFSC=0.11 +LZFPC=0.46 + </pre><p class="prec">Example SacParamSet Block</p> + <span class="namec">GAUGE:</span> This is the name of the gauge location block for which the parameters that follow it will be applied.<br /> + <span class="namec">UZTWM:</span> Upper zone tension water maximum (mm)<br /> + <span class="namec">UZFWM:</span> Upper zone free water maximum (mm)<br /> + <span class="namec">UZK:</span> Fractional daily upper zone free water withdrawal rate<br /> + <span class="namec">PCTIM:</span> Minimum impervious area (%)<br /> + <span class="namec">ADIMP:</span> Additional impervious area (%)<br /> + <span class="namec">RIVA:</span> Riparian vegetation area (%)<br /> + <span class="namec">ZPERC:</span> Maximum percolation rate<br /> + <span class="namec">REXP:</span> Exponent for the percolation equation<br /> + <span class="namec">LZTWM:</span> Lower zone tension water capacity (mm)<br /> + <span class="namec">LZFSM:</span> Lower zone supplemental free water capacity (mm)<br /> + <span class="namec">LZFPM:</span> Lower zone primary free water capacity (mm)<br /> + <span class="namec">LZSK:</span> Fractional daily supplemental withdrawal rate<br /> + <span class="namec">LZPK:</span> Fractional daily primary withdrawal rate<br /> + <span class="namec">PFREE:</span> Percent of percolated water which always goes directly to lower zone free water storages (%)<br /> + <span class="namec">SIDE:</span> Ratio of non-channel baseflow (deep recharge) to channel (visible) baseflow<br /> + <span class="namec">RSERV:</span> Percent of lower zone free water which cannot be transferred to lower zone tension water (%)<br /> + <span class="namec">ADIMC:</span> Tension water contents of the ADIMP area (mm)<br /> + <span class="namec">UZTWC:</span> Upper zone tension water contents (mm)<br /> + <span class="namec">UZFWC:</span> Upper zone free water contents (mm)<br /> + <span class="namec">LZTWC:</span> Lower zone tension water contents (mm)<br /> + <span class="namec">LZFSC:</span> Lower zone free supplemental contents (mm)<br /> + <span class="namec">LZFPC:</span> Lower zone free primary contents (mm)<br /><br /> + <li><a name="paramhp">HP Parameter Set</a></li> + To be completed in a future revision.<br /><br /> + <li><a name="paramlr">Linear Reservoir Parameter Set</a></li> + <pre> +[lrparamset rundu] +gauge=rundu +coem=1611.115479 +river=307.980042 +under=2531.556641 +leako=0.918236 +leaki=0.017568 +th=8.140809 +iso=0.000040 +isu=0.000073 + </pre> + To be completed in a future revision<br /><br /> + <li><a name="paramkw">Kinematic Wave Parameter Set</a></li> + <pre> +[KWParamSet rundu] +GAUGE=rundu +UNDER=1.673110 +LEAKI=0.043105 +TH=6.658569 +ISU=0.000000 +ALPHA=2.991570 +BETA=0.932080 +ALPHA0=4.603945 + </pre><p class="prec">Example KWParamSet Block</p> + <span class="namec">GAUGE:</span> This is the name of the gauge location block for which the parameters that follow it will be applied.<br /> + <span class="namec">TH:</span> The number of grid cells needed to flow into a cell for it to be declared a channel grid cell.<br /> + <span class="namec">UNDER:</span> The interflow flow speed multiplier<br /> + <span class="namec">LEAKI:</span> The amount of water leaked out of the interflow reservoir at each time step. Ranges between 0 and 1.<br /> + <span class="namec">ISU:</span> The initial value of the interflow reservoir.<br /> + <span class="namec">ALPHA:</span> The multiplier in Q = alpha*A<sup>beta</sup> used for channel routing<br /> + <span class="namec">BETA:</span> The exponent in Q = alpha*A<sup>beta</sup> used for channel routing<br /> + <span class="namec">ALPHA0:</span> The Alpha value used for overland routing.<br /><br /> + <li><a name="paramsnow17">Snow-17 Parameter Set</a></li> + <pre> +[snow17paramset tarbela] +GAUGE=tarbela +UADJ=0.184653 +MBASE=0.047224 +MFMAX=1.068658 +MFMIN=0.516059 +TIPM=0.911706 +NMF=0.077336 +PLWHC=0.093812 +SCF=2.219492 + </pre><p class="prec">Example Snow17ParamSet Block</p> + <span class="namec">GAUGE:</span> This is the name of the gauge location block for which the parameters that follow it will be applied.<br /> + <span class="namec">UADJ:</span> The number of grid cells needed to flow into a cell for it to be declared a channel grid cell.<br /> + <span class="namec">MBASE:</span> The interflow flow speed multiplier<br /> + <span class="namec">MFMAX:</span> The amount of water leaked out of the interflow reservoir at each time step. Ranges between 0 and 1.<br /> + <span class="namec">MFMIN:</span> The initial value of the interflow reservoir.<br /> + <span class="namec">TIPM:</span> The multiplier in Q = alpha*A<sup>beta</sup> used for channel routing<br /> + <span class="namec">NMF:</span> The exponent in Q = alpha*A<sup>beta</sup> used for channel routing<br /> + <span class="namec">PLWHC:</span> The Alpha value used for overland routing.<br /> + <span class="namec">SCF:</span> The Alpha value used for overland routing.<br /><br /> + <li><a name="paramsi">Simple Inundation Parameter Set</a></li> + <pre> +[simpleinundationparamset rundu] +gauge=rundu +alpha=2.991570 +beta=0.932080 + </pre><p class="prec">Example SimpleInundationParamSet Block</p> + <span class="namec">GAUGE:</span> This is the name of the gauge location block for which the parameters that follow it will be applied.<br /> + <span class="namec">ALPHA:</span> The multiplier in A = (Q/alpha)<sup>1/beta</sup> used for computing cross-sectional area<br /> + <span class="namec">BETA:</span> The exponent in A = (Q/alpha)<sup>1/beta</sup> used for computing cross-sectional area<br /><br /> + </ol> + <li><a name="task">Tasks</a></li> + <p>Tasks define the necessary information about which model to run, over what time period to run, with what time step to run, etc.</p> +<pre>[Task RunFF] +STYLE=SIMU +MODEL=CREST +BASIN=FF +PRECIP=Q2_PRECIP +PET=PET +OUTPUT=/EF5Demo/FF/output/ +PARAM_SET=FF +TIMESTEP=5u +TIME_BEGIN=201006010000 +TIME_END=201006010030 +</pre><p class="prec">Example Task Block</p> + + <span class="namec">STYLE:</span> The style of task that this is. Possible values are:<br /> + <pre class="valuec"> +<em>SIMU</em>: A simulation run. +<em>SIMU_RP</em>: A simulation run that will produce standard deviation, average and skew coefficient grids for estimating return period. +<em>CALI_DREAM</em>: A calibration run using DREAM. +<em>CLIP_BASIN</em>: Clips the basic files to the specified BASIN. +<em>CLIP_GAUGE</em>: Clips the basic files to the first specified gauge.</pre> + <span class="namec">MODEL:</span> The water balance model that this task should use. Possible values are:<br /> + <pre class="valuec"> +<em>CREST</em>: The Coupled Routing and Excess STorage distributed hydrological model. +<em>SAC</em>: The SAC-SMA model. +<em>HyMOD</em>: HyMod.</pre> + <span class="namec">ROUTING:</span> The routing method that this task should use. Possible values are:<br /> + <pre class="valuec"> +<em>KW</em>: Kinematic Wave Routing. +<em>LR</em>: Linear Reservoir Routing.</pre> + <span class="namec">SNOW:</span> <em>(Optional)</em> The snow melt model that this task should use. Possible values are:<br /> + <pre class="valuec"><em>SNOW17</em>: The Snow-17 snow melt model.</pre> + <span class="namec">INUNDATION:</span> <em>(Optional)</em> The inundation model that this task should use. Possible values are:<br /> + <pre class="valuec"><em>SIMPLEINUNDATIOn</em>: The Simple Inundation model.</pre> + <span class="namec">BASIN:</span> The basin block name which defines the area over which the model should be run.<br /> + <span class="namec">DEFAULTPARAMSGAUGE:</span> <em>(Optional)</em> The gauge for which parameters are specified and used for gauges which did not have parameters specified. Useful when modeling large areas with gridded parameters.<br /> + <span class="namec">PRECIP:</span> The precipitation block name which defines the precipitation.<br /> + <span class="namec">PRECIPFORECAST:</span> <em>(Optional)</em> The precipitation block name which defines the forecast precipitation. Used if the precipiation specified in PRECIP is unavailable for the current time.<br /> + <span class="namec">TEMP:</span> <em>(Required if using SNOW)</em> The temperature block name which defines the temperature data to be used.<br /> + <span class="namec">TEMPFORECAST:</span> <em>(Optional if using SNOW)</em> The temperature block name which defines the forecast temperatures. Used if the temperature specified in TEMP is unavailable for the current time.<br /> + <span class="namec">PET:</span> The PET block name which defines the PET to use.<br /> + <span class="namec">PARAM_SET:</span> The parameter set block name which defines which set of water balance parameters to use.<br /> + <span class="namec">ROUTING_PARAM_SET:</span> The parameter set block name which defines which set of routing parameters to use.<br /> + <span class="namec">SNOW_PARAM_SET:</span> <em>(Required if using SNOW)</em> The parameter set block name which defines which set of snow parameters to use.<br /> + <span class="namec">INUNDATION_PARAM_SET:</span> <em>(Required if using INUNDATION)</em> The parameter set block name which defines which set of inundation parameters to use.<br /> + <span class="namec">CALI_PARAM:</span> <em>(Required if using CALI_DREAM)</em> The parameter set block name which defines which set of water balance parameters settings for calibration.<br /> + <span class="namec">ROUTING_CALI_PARAM:</span> <em>(Required if using CALI_DREAM)</em> The parameter set block name which defines which set of routing parameters to use for calibration.<br /> + <span class="namec">SNOW_CALI_PARAM:</span> <em>(Required if using SNOW, CALI_DREAM)</em> The parameter set block name which defines which set of snow parameters to use for calibration.<br /> + <span class="namec">INUNDATION_CALI_PARAM:</span> <em>(Required if using INUNDATION, CALI_DREAM)</em> The parameter set block name which defines which set of inundation parameters to use for calibration.<br /> + <span class="namec">PRELOAD_FILE:</span> <em>(Optional)</em> The file path and name where for the preload file. The preload file contains the forcings (Precip, PET, Temp) defined for the current time period and basin extent. Generated by EF5 if it does not exist. Useful for faster runs when forcings are not changing such as with manual calibration.<br /> + <span class="namec">STATES:</span> <em>(Optional)</em> The location where output files should be written.<br /> + <span class="namec">TIMESTEP:</span> The time step to use when running the model. Supported time units are year (y), month (m), day (d), hour (h), minute (u) and second (s).<br /> + <span class="namec">TIME_BEGIN:</span> The initialization time for the model run. YYYYMMDDHHUUSS format.<br /> + <span class="namec">TIME_END:</span> The ending time for the model run. YYYYMMDDHHUUSS format.<br /> + <span class="namec">TIME_WARMEND:</span> The end of the warm-up period. YYYYMMDDHHUUSS format.<br /> + <span class="namec">TIME_STATE:</span> <em>(Optional)</em> The time at which to output model states. YYYYMMDDHHUUSS format.<br /> + <span class="namec">OUTPUT:</span> The location where output files should be written.<br /> + <span class="namec">OUTPUT_GRIDS:</span> <em>(Optional)</em> Which grids should be output, combine together with | :<br /> + <pre class="valuec"> +<em>NONE</em>: No gridded output. +<em>STREAMFLOW</em>: Streamflow (cms) +<em>SOILMOISTURE</em>: Soil moisture (%) +<em>RETURNPERIOD</em>: Streamflow return period (years) +<em>PRECIP</em>: Precipitaiton (mm) +<em>PET</em>: Potential evapotranspiration (mm) +<em>SNOWWATER</em>: Snow water equivalent from the snow melt model (mm) +<em>TEMPERATURE</em>: Temperature (C) +<em>INUNDATION</em>: Water depth (m) +<em>MAXSTREAMFLOW</em>: Maximum streamflow during run (cms) +<em>MAXSOILMOISTURE</em>: Maximum soil moisture during run (%) +<em>MAXRETURNPERIOD</em>: Maximum return period during run (years) +<em>MAXSNOWWATER</em>: Maximum snow water equivalent (mm)</pre> + <span class="namec">DA_FILE:</span> <em>(Optional)</em> The input observations to be added for use with streamflow data assimilation,<br /> + <span class="namec">CO_FILE:</span> <em>(Optional)</em> The combined output file if one is desired.<br /> + <span class="namec">RP_STDGRID:</span> <em>(Optional)</em> The geotiff file representing the standard deviation for the Log-Pearson Type III return period distribution.<br /> + <span class="namec">RP_AVGGRID:</span> <em>(Optional)</em> The geotiff file representing the average for the Log-Pearson Type III return period distribution.<br /> + <span class="namec">RP_CSGRID:</span> <em>(Optional)</em> The geotiff file representing the skew coefficient for the Log-Pearson Type III return period distribution.<br /> + <li><a name="execute">Execute Block</a></li> + <p>The execute block defines which tasks to run when the ef5 program is executed</p> +<pre>[Execute] +TASK=RunFF +</pre><p class="prec">Example Execute Block</p> + <span class="namec">TASK:</span> The task block name which should be executed.<br /><br /> + </ol> + <li><a name="run">Running EF5</a></li> + <pre class="pree">ef5 [controlfile]</pre> + <p>Running ef5 is straight forwarded, you can called the executable with no arguments and it will assume a default configuration file name of "control.txt" in the current working directory or you can pass in a configuration file name as an argument.</p> + <li><a name="cali">Calibrating the Models</a></li> + <p>This section will be filled in once calibration methods are implemented.</p> + <li>Appendix</li> + <ol> + <li><a name="cconfig">Complete Sample Configuration File</a></li> + <pre> +/* + * This is an example configuration file for EF5 + */ + +[Basic] +DEM=/EF5Demo/FF/basic/DEM.asc +DDM=/EF5Demo/FF/basic/DDM.asc +FAM=/EF5Demo/FF/basic/FAM.asc +PROJ=laea +ESRIDDM=true + +[PrecipForcing Q2Precip] +TYPE=BIF +UNIT=mm/h +FREQ=5u +LOC=/EF5Demo/FF/precip +NAME=Q2_YYYYMMDDHHUU.bif + +[PETForcing PET] +TYPE=BIF +UNIT=mm/h +FREQ=m +LOC=/EF5Demo/FF/pet +NAME=PET_MM.bif + +[Gauge OKC] +LON=-97.01 +LAT=35.68 +OBS=/EF5Demo/obs/okc.csv + +[Gauge AR] +LON=-93.62 +LAT=34.37 + +[Basin FF] +GAUGE=OKC +GAUGE=AR + +[CrestParamSet FF] +GAUGE=AR +COEM=24.230076 EXPM=0.502391 RIVER=1.73056 +UNDER=0.291339 LEAKO=0.56668 LEAKI=0.251648 +TH=63.20205 GM=1.364364 PWM=71.96465 +PB=0.964355 PIM=6.508687 PKE=0.19952 +PFC=2.578529 IWU=53.52593 ISO=5.899539 +ISU=17.31128 +GAUGE=OKC +COEM=24.230076 EXPM=0.502391 RIVER=1.73056 +UNDER=0.291339 LEAKO=0.56668 LEAKI=0.251648 +TH=63.20205 GM=1.364364 PWM=71.96465 +PB=0.964355 PIM=6.508687 PKE=0.19952 +PFC=2.578529 IWU=53.52593 ISO=5.899539 +ISU=17.31128 + +[Task RunFF] +STYLE=SIMU +MODEL=CREST +BASIN=FF +PRECIP=Q2_PRECIP +PET=PET +OUTPUT=/EF5Demo/FF/output/ +PARAM_SET=FF +TIMESTEP=5u +TIME_BEGIN=201006010000 +TIME_END=201006010030 + +[Execute] +TASK=RunFF</pre><p class="prec">Example of a full EF5 configuration file.</p> + </ol> + </ol> + </div> + </body> +</html> diff --git a/src/ARS.cpp b/src/ARS.cpp new file mode 100755 index 0000000..ed28f07 --- /dev/null +++ b/src/ARS.cpp @@ -0,0 +1,173 @@ +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <stdlib.h> +#include "ARS.h" + +void ARS::Initialize(CaliParamConfigSection *caliParamConfigNew, RoutingCaliParamConfigSection *routingCaliParamConfigNew, SnowCaliParamConfigSection *snowCaliParamConfigNew, int numParamsWBNew, int numParamsRNew, int numParamsSNew, Simulator *simNew) { + caliParamConfig = caliParamConfigNew; + routingCaliParamConfig = routingCaliParamConfigNew; + numParamsWB = numParamsWBNew; + numParamsR = numParamsR; + numParams = numParamsWBNew + numParamsRNew; + sim = simNew; + + // Create storage arrays + minParams = new float[numParams]; + maxParams = new float[numParams]; + currentParams = new float[numParams]; + + // Stuff from CaliParamConfigSection + memcpy(minParams, caliParamConfig->GetParamMins(), sizeof(float)*numParams); + memcpy(maxParams, caliParamConfig->GetParamMaxs(), sizeof(float)*numParams); + goal = objectiveGoals[caliParamConfig->GetObjFunc()]; + + // Configurable Parameters + topNum = caliParamConfig->ARSGetTopNum(); + minObjScore = caliParamConfig->ARSGetCritObjScore(); + convergenceCriteria = caliParamConfig->ARSGetConvCriteria(); + burnInSets = caliParamConfig->ARSGetBurnInSets(); + + // Initialize vars & RNG + totalSets = 0; + goodSets = 0; +#ifdef WIN32 + srand(time(NULL)); +#else + srand48(time(NULL)); +#endif + +} + +void ARS::CalibrateParams() { + + float objScore; + float scoreDiff = 0; + + while(goodSets < burnInSets || scoreDiff > convergenceCriteria) { + + // Generate new parameters + for (int i = 0; i < numParams; i++) { +#ifdef WIN32 + float randVal = ((float)rand()) / RAND_MAX; +#else + float randVal = drand48(); //((float)rand()) / RAND_MAX; +#endif + currentParams[i] = minParams[i] + (maxParams[i] - minParams[i]) * randVal; + } + + objScore = sim->SimulateForCali(currentParams); + //printf("%f\n", objScore); + + + totalSets++; + + if (!(totalSets % 500)) { + printf("Total sets %i, good sets %i!\n", totalSets, goodSets); + } + + if (((goal == OBJECTIVE_GOAL_MAXIMIZE) && objScore < minObjScore) || ((goal == OBJECTIVE_GOAL_MINIMIZE) && objScore > minObjScore)) { + continue; + } else { + // This is a good parameter set, count it towards the burn in total! + goodSets++; + } + + + bool insertedParams = false; + for (std::list<ARS_INFO *>::iterator itr = topSets.begin(); itr != topSets.end(); itr++) { + ARS_INFO *current = *itr; + // Add this sucker here, it is a winner! + if (((goal == OBJECTIVE_GOAL_MAXIMIZE) && objScore > current->objScore) || ((goal == OBJECTIVE_GOAL_MINIMIZE) && objScore < current->objScore)) { + ARS_INFO *newInfo = new ARS_INFO; + newInfo->params = new float[numParams]; + memcpy(newInfo->params, currentParams, sizeof(float)*numParams); + newInfo->objScore = objScore; + topSets.insert(itr, newInfo); + insertedParams = true; + break; + } + } + + // Lets see if the top number of sets hasn't filled yet, if so add it to the back + if (!insertedParams && topSets.size() < topNum) { + ARS_INFO *newInfo = new ARS_INFO; + newInfo->params = new float[numParams]; + memcpy(newInfo->params, currentParams, sizeof(float)*numParams); + newInfo->objScore = objScore; + topSets.push_back(newInfo); + insertedParams = true; + } + + // Ensure that our list of good parameter sets only contains topNum + if (topSets.size() > topNum) { + ARS_INFO *current = topSets.back(); + delete [] current->params; + delete current; + topSets.pop_back(); + } + + // Update the min and max values! + if (goodSets > burnInSets && insertedParams) { + + for (int i = 0; i < numParams; i++) { + minParams[i] = 9999; + maxParams[i] = 0; + } + + for (std::list<ARS_INFO *>::iterator itr = topSets.begin(); itr != topSets.end(); itr++) { + ARS_INFO *current = *itr; + for (int i = 0; i < numParams; i++) { + if (current->params[i] < minParams[i]) { + minParams[i] = current->params[i]; + } + if (current->params[i] > maxParams[i]) { + maxParams[i] = current->params[i]; + } + } + } + } + + ARS_INFO *top = topSets.front(); + ARS_INFO *bottom = topSets.back(); + if (insertedParams) { + scoreDiff = top->objScore - bottom->objScore; + printf("ConvC %f (%f, %f), total runs %i, good runs %i\n", (top->objScore - bottom->objScore), top->objScore, bottom->objScore, totalSets, goodSets); + } + + } +} + + +void ARS::WriteOutput(char *outputFile, MODELS model, ROUTES route) { + FILE *file = fopen(outputFile, "w"); + + fprintf(file, "%s", "Rank,ObjFunc,"); + for (int i = 0; i < numParams; i++) { + fprintf(file, "%s%s", modelParamStrings[model][i], (i != (numParams-1)) ? "," : "\n"); + } + + int index = 0; + for (std::list<ARS_INFO *>::iterator itr = topSets.begin(); itr != topSets.end(); itr++) { + ARS_INFO *current = *itr; + + fprintf(file, "%i,%f,", index, current->objScore); + + for (int i = 0; i < numParams; i++) { + fprintf(file, "%f%s", current->params[i], (i != (numParams-1)) ? "," : "\n"); + } + + index++; + } + + fprintf(file, "%s", "\n\n\n"); + + ARS_INFO *current = *(topSets.begin()); + for (int i = 0; i < numParams; i++) { + fprintf(file, "%s=%f\n", modelParamStrings[model][i], current->params[i]); + } + + + fclose(file); +} + diff --git a/src/ARS.h b/src/ARS.h new file mode 100755 index 0000000..563a8ad --- /dev/null +++ b/src/ARS.h @@ -0,0 +1,35 @@ +#ifndef ARS_H +#define ARS_H + +#include <list> +#include "Calibrate.h" +#include "Model.h" + +struct ARS_INFO { + float objScore; + float *params; +}; + +class ARS : public Calibrate { + public: + //ARS(int numParamsNew, int topNumNew, float *currentParamsNew, float *minParamsNew, float *maxParamsNew, OBJECTIVE_GOAL goalNew); + void Initialize(CaliParamConfigSection *caliParamConfigNew, RoutingCaliParamConfigSection *routingCaliParamConfigNew, SnowCaliParamConfigSection *snowCaliParamConfigNew, int numParamsWBNew, int numParamsRNew, int numParamsSNew, Simulator *simNew); + void CalibrateParams(); + void WriteOutput(char *outputFile, MODELS model, ROUTES route); + + private: + float *minParams; + float *maxParams; + float *currentParams; + OBJECTIVE_GOAL goal; + std::list<ARS_INFO *> topSets; + int numParams; + unsigned int topNum; + float minObjScore; + float convergenceCriteria; + int goodSets; + int burnInSets; + int totalSets; +}; + +#endif diff --git a/src/AscGrid.cpp b/src/AscGrid.cpp new file mode 100755 index 0000000..6e4fade --- /dev/null +++ b/src/AscGrid.cpp @@ -0,0 +1,212 @@ +#include <cstdio> +#include <fcntl.h> +#include "Messages.h" +#include "AscGrid.h" + +LongGrid *ReadLongAscGrid(char *file) { + + LongGrid *grid = NULL; + FILE *fileH; + + fileH = fopen(file, "r"); + if (fileH == NULL) { + return NULL; + } + + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_SEQUENTIAL); + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_WILLNEED); + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_NOREUSE); + + grid = new LongGrid(); + + if (fscanf(fileH, "%*s %ld", &grid->numCols) != 1) { + delete grid; + return NULL; + } + if (fscanf(fileH, "%*s %ld", &grid->numRows) != 1) { + delete grid; + return NULL; + } + if (fscanf(fileH, "%*s %e", &grid->extent.left) != 1) { + delete grid; + return NULL; + } + if (fscanf(fileH, "%*s %e", &grid->extent.bottom) != 1) { + delete grid; + return NULL; + } + if (fscanf(fileH, "%*s %e", &grid->cellSize) != 1) { + delete grid; + return NULL; + } + if (fscanf(fileH, "%*s %ld", &grid->noData) != 1) { + delete grid; + return NULL; + } + + grid->data = new long*[grid->numRows]; + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new long[grid->numCols]; + } + + for (long row = 0; row < grid->numRows; row++) { + for (long col = 0; col < grid->numCols; col++) { + fscanf(fileH, "%ld", &grid->data[row][col]); + } + } + + //Fill in the rest of the BoundingBox + grid->extent.top = grid->extent.bottom + grid->numRows*grid->cellSize; + grid->extent.right = grid->extent.left + grid->numCols*grid->cellSize; + + fclose(fileH); + + return grid; +} + +FloatGrid *ReadFloatAscGrid(char *file) { + + FloatGrid *grid = NULL; + + FILE *fileH; + + fileH = fopen(file, "r"); + if (fileH == NULL) { + return NULL; + } + + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_SEQUENTIAL); + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_WILLNEED); + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_NOREUSE); + + grid = new FloatGrid(); + + if (fscanf(fileH, "%*s %ld", &grid->numCols) != 1) { + WARNING_LOGF("ASCII file %s missing number of columns", file); + delete grid; + fclose(fileH); + return NULL; + } + if (fscanf(fileH, "%*s %ld", &grid->numRows) != 1) { + WARNING_LOGF("ASCII file %s missing number of rows", file); + delete grid; + fclose(fileH); + return NULL; + } + if (fscanf(fileH, "%*s %e", &grid->extent.left) != 1) { + WARNING_LOGF("ASCII file %s missing lower left x", file); + delete grid; + fclose(fileH); + return NULL; + } + if (fscanf(fileH, "%*s %e", &grid->extent.bottom) != 1) { + WARNING_LOGF("ASCII file %s missing lower left y", file); + delete grid; + fclose(fileH); + return NULL; + } + if (fscanf(fileH, "%*s %e", &grid->cellSize) != 1) { + WARNING_LOGF("ASCII file %s missing cell size", file); + delete grid; + fclose(fileH); + return NULL; + } + if (fscanf(fileH, "%*s %f", &grid->noData) != 1) { + WARNING_LOGF("ASCII file %s missing no data value", file); + delete grid; + fclose(fileH); + return NULL; + } + + grid->data = new float*[grid->numRows](); + if (!grid->data) { + WARNING_LOGF("ASCII file %s too large (out of memory) with %li rows", file, grid->numRows); + delete grid; + fclose(fileH); + return NULL; + } + + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new float[grid->numCols]; + if (!grid->data[i]) { + WARNING_LOGF("ASCII file %s too large (out of memory) with %li columns", file, grid->numCols); + delete grid; + fclose(fileH); + return NULL; + } + } + + for (long row = 0; row < grid->numRows; row++) { + for (long col = 0; col < grid->numCols; col++) { + fscanf(fileH, "%f", &grid->data[row][col]); + } + } + + //Fill in the rest of the BoundingBox + grid->extent.top = grid->extent.bottom + grid->numRows*grid->cellSize; + grid->extent.right = grid->extent.left + grid->numCols*grid->cellSize; + + fclose(fileH); + + return grid; +} + +void WriteLongAscGrid(const char *file, LongGrid *grid) { + FILE *fileH; + + fileH = fopen(file, "w"); + if (fileH == NULL) { + printf("OMG!\n"); + return; + } + + // Write out the header info + fprintf(fileH, "ncols %ld\n", grid->numCols); + fprintf(fileH, "nrows %ld\n", grid->numRows); + fprintf(fileH, "xllcorner %f\n", grid->extent.left); + fprintf(fileH, "yllcorner %f\n", grid->extent.bottom); + fprintf(fileH, "cellsize %f\n", grid->cellSize); + fprintf(fileH, "NODATA_value %ld\n", grid->noData); + + + //Write out the data + for (long row = 0; row < grid->numRows; row++) { + long lastCol = grid->numCols - 1; + for (long col = 0; col < grid->numCols; col++) { + fprintf(fileH, "%5ld%s", grid->data[row][col], (col == lastCol) ? "\n" : " "); + } + } + + fclose(fileH); + +} + +void WriteFloatAscGrid(const char *file, FloatGrid *grid) { + FILE *fileH; + + fileH = fopen(file, "w"); + if (fileH == NULL) { + printf("OMG!\n"); + return; + } + + // Write out the header info + fprintf(fileH, "ncols %ld\n", grid->numCols); + fprintf(fileH, "nrows %ld\n", grid->numRows); + fprintf(fileH, "xllcorner %f\n", grid->extent.left); + fprintf(fileH, "yllcorner %f\n", grid->extent.bottom); + fprintf(fileH, "cellsize %f\n", grid->cellSize); + fprintf(fileH, "NODATA_value %.02f\n", grid->noData); + + + //Write out the data + for (long row = 0; row < grid->numRows; row++) { + long lastCol = grid->numCols - 1; + for (long col = 0; col < grid->numCols; col++) { + fprintf(fileH, "%.05f%s", grid->data[row][col], (col == lastCol) ? "\n" : " "); + } + } + + fclose(fileH); + +} diff --git a/src/AscGrid.h b/src/AscGrid.h new file mode 100755 index 0000000..c073b6f --- /dev/null +++ b/src/AscGrid.h @@ -0,0 +1,11 @@ +#ifndef ASC_GRID_H +#define ASC_GRID_H + +#include "Grid.h" + +LongGrid *ReadLongAscGrid(char *file); +FloatGrid *ReadFloatAscGrid(char *file); +void WriteLongAscGrid(const char *file, LongGrid *grid); +void WriteFloatAscGrid(const char *file, FloatGrid *grid); + +#endif diff --git a/src/BIFClip.cpp b/src/BIFClip.cpp new file mode 100644 index 0000000..6ee68fc --- /dev/null +++ b/src/BIFClip.cpp @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "BifGrid.h" +#include "AscGrid.h" + +int main(int argc, char *argv[]) { + + if (argc != 3) { + printf("Use this program as BIFClip <input_filename> <output_filename>\n"); + return 0; + } + + char *filename = argv[1]; + char *outputfile = argv[2]; + + FloatGrid *precipGrid = ReadFloatBifGrid(filename); + + if (!precipGrid) { + printf("Failed to open file %s\n", filename); + return 0; + } + + WriteFloatAscGrid(outputfile, precipGrid); + + return 1; +} diff --git a/src/BasicConfigSection.cpp b/src/BasicConfigSection.cpp new file mode 100755 index 0000000..9ad4a5a --- /dev/null +++ b/src/BasicConfigSection.cpp @@ -0,0 +1,112 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "BasicConfigSection.h" + +BasicConfigSection *g_basicConfig; + +BasicConfigSection::BasicConfigSection() { + DEMSet = false; + DDMSet = false; + FAMSet = false; + projectionSet = false; + esriDDMSet = false; + selfFAMSet = false; +} + +BasicConfigSection::~BasicConfigSection() { + +} + +char *BasicConfigSection::GetDEM() { + return DEM; +} + +char *BasicConfigSection::GetDDM() { + return DDM; +} + +char *BasicConfigSection::GetFAM() { + return FAM; +} + +PROJECTIONS BasicConfigSection::GetProjection() { + return projection; +} + +CONFIG_SEC_RET BasicConfigSection::ProcessKeyValue(char *name, char *value) { + + if (!strcasecmp(name, "dem")) { + strcpy(DEM, value); + DEMSet = true; + } else if (!strcasecmp(name, "ddm")) { + strcpy(DDM, value); + DDMSet = true; + } else if (!strcasecmp(name, "fam")) { + strcpy(FAM, value); + FAMSet = true; + } else if (!strcasecmp(name, "proj")) { + if (!strcasecmp(value, "geographic")) { + projection = PROJECTION_GEOGRAPHIC; + projectionSet = true; + } else if (!strcasecmp(value, "laea")) { + projection = PROJECTION_LAEA; + projectionSet = true; + } else { + ERROR_LOGF("Unknown projection option \"%s\"", value); + INFO_LOGF("Valid projection options are \"%s\"", "GEOGRAPHIC, LAEA"); + return INVALID_RESULT; + } + } else if (!strcasecmp(name, "esriddm")) { + if (!strcasecmp(value, "true")) { + esriDDM = true; + esriDDMSet = true; + } else if (!strcasecmp(value, "false")) { + esriDDM = false; + esriDDMSet = true; + } else { + ERROR_LOGF("Unknown ESRI DDM option \"%s\"", value); + INFO_LOGF("Valid ESRI DDM options are \"%s\"", "TRUE, FALSE"); + return INVALID_RESULT; + } + } else if (!strcasecmp(name, "selffam")) { + if (!strcasecmp(value, "true")) { + selfFAM = true; + selfFAMSet = true; + } else if (!strcasecmp(value, "false")) { + selfFAM = false; + selfFAMSet = true; + } else { + ERROR_LOGF("Unknown Self FAM option \"%s\"", value); + INFO_LOGF("Valid Self FAM options are \"%s\"", "TRUE, FALSE"); + return INVALID_RESULT; + } + } else { + ERROR_LOGF("Unknown name-key pair \"%s\"", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET BasicConfigSection::ValidateSection() { + if (!DEMSet) { + ERROR_LOG("The DEM was not specified"); + return INVALID_RESULT; + } else if (!DDMSet) { + ERROR_LOG("The DDM was not specified"); + return INVALID_RESULT; + } else if (!FAMSet) { + ERROR_LOG("The FAM was not specified"); + return INVALID_RESULT; + } else if (!projectionSet) { + ERROR_LOG("The projection was not specified"); + return INVALID_RESULT; + } else if (!esriDDMSet) { + ERROR_LOG("The type of DDM (ESRIDDM) was not specified"); + return INVALID_RESULT; + } else if (!selfFAMSet) { + ERROR_LOG("If the FAM includes the current grid cell in the accumulation (SELFFAM) was not specified"); + return INVALID_RESULT; + } + return VALID_RESULT; +} diff --git a/src/BasicConfigSection.h b/src/BasicConfigSection.h new file mode 100755 index 0000000..793db29 --- /dev/null +++ b/src/BasicConfigSection.h @@ -0,0 +1,36 @@ +#ifndef CONFIG_BASIC_SECTION +#define CONFIG_BASIC_SECTION + +#include "Defines.h" +#include "ConfigSection.h" +#include "Projection.h" + +class BasicConfigSection : public ConfigSection { + + public: + BasicConfigSection(); + ~BasicConfigSection(); + + char *GetDEM(); + char *GetDDM(); + char *GetFAM(); + PROJECTIONS GetProjection(); + bool IsESRIDDM() { return esriDDM; } + bool IsSelfFAM() { return selfFAM; } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + private: + bool DEMSet, DDMSet, FAMSet, projectionSet, esriDDMSet, selfFAMSet; + bool esriDDM, selfFAM; + char DEM[CONFIG_MAX_LEN]; + char DDM[CONFIG_MAX_LEN]; + char FAM[CONFIG_MAX_LEN]; + PROJECTIONS projection; + + +}; + +extern BasicConfigSection *g_basicConfig; + +#endif diff --git a/src/BasicGrids.cpp b/src/BasicGrids.cpp new file mode 100755 index 0000000..24b9f94 --- /dev/null +++ b/src/BasicGrids.cpp @@ -0,0 +1,1465 @@ +#include <cstdio> +#include <algorithm> +#include <stack> +#include <list> +#include <map> +#include <cstring> +#include <climits> +#include <cmath> +#include <stdlib.h> +#include "AscGrid.h" +#include "TifGrid.h" +#include "BasicConfigSection.h" +#include "Defines.h" +#include "Messages.h" +#include "BasicGrids.h" + +FloatGrid *g_DEM; +FloatGrid *g_DDM; +FloatGrid *g_FAM; +Projection *g_Projection; + +struct FAMSearch { + long x; + long y; + bool used; + long fa; +}; + +//static FAMSearch *NextUnusedGrid(std::vector<FAMSearch *> *gridCells); +static bool GetDownstreamHeight(long x, long y, long *outsideHeight); +static bool TestUpstream(GridNode *node, FLOW_DIR dir, GridLoc *loc); +static bool TestUpstream(long nextX, long nextY, FLOW_DIR dir, GridLoc *loc); +static bool TestUpstreamBroken(long nextX, long nextY, FLOW_DIR dir, GridLoc *loc); +static GaugeConfigSection *FindGauge(std::map<unsigned long, GaugeConfigSection *> *gauges, GridNode *node); +static GaugeConfigSection *NextUnusedGauge(std::vector<GaugeConfigSection *> *gauges); +static bool SortByFlowAccumFS(FAMSearch *fs1, FAMSearch *fs2); +static bool SortByFlowAccum(GaugeConfigSection *d1, GaugeConfigSection *d2); +static void FixFAM(); +static int FlowsOut(long nextX, long nextY, FLOW_DIR dir, long currentHeight); +static int FlowsIn(long nextX, long nextY, FLOW_DIR dir, long currentHeight, GridLoc *locIn, long maxSearch, GridLoc *locOut); +static void FixFlowDir(BasinConfigSection *basin, std::vector<GridNode> *nodes); +/*FLOW_DIR reverseDir[] = { + FLOW_SOUTH, + FLOW_SOUTHWEST, + FLOW_WEST, + FLOW_NORTHWEST, + FLOW_NORTH, + FLOW_NORTHEAST, + FLOW_EAST, + FLOW_SOUTHEAST, + FLOW_QTY };*/ + +FLOW_DIR reverseDir[] = { + FLOW_WEST, + FLOW_SOUTHWEST, + FLOW_SOUTH, + FLOW_SOUTHEAST, + FLOW_EAST, + FLOW_NORTHEAST, + FLOW_NORTH, + FLOW_NORTHWEST, + FLOW_QTY }; + +//This function loads the basic grids and also initializes the projection! +bool LoadBasicGrids() { + + INFO_LOGF("Loading DEM: %s", g_basicConfig->GetDEM()); + char *ext = strrchr(g_basicConfig->GetDEM(), '.'); + if (!strcasecmp(ext, ".asc")) { + g_DEM = ReadFloatAscGrid(g_basicConfig->GetDEM()); + } else { + g_DEM = ReadFloatTifGrid(g_basicConfig->GetDEM()); + } + if (!g_DEM) { + ERROR_LOG("Failed to load DEM!"); + return false; + } + + INFO_LOGF("Loading DDM: %s", g_basicConfig->GetDDM()); + ext = strrchr(g_basicConfig->GetDDM(), '.'); + if (!strcasecmp(ext, ".asc")) { + g_DDM = ReadFloatAscGrid(g_basicConfig->GetDDM()); + } else { + g_DDM = ReadFloatTifGrid(g_basicConfig->GetDDM()); + } + if (!g_DDM) { + ERROR_LOG("Failed to load DDM!"); + return false; + } + if (!g_DEM->IsSpatialMatch(g_DDM)) { + ERROR_LOG("The spatial characteristics of the DEM and DDM differ!"); + return false; + } + + INFO_LOGF("Loading FAM: %s", g_basicConfig->GetFAM()); + ext = strrchr(g_basicConfig->GetFAM(), '.'); + if (!strcasecmp(ext, ".asc")) { + g_FAM = ReadFloatAscGrid(g_basicConfig->GetFAM()); + } else { + g_FAM = ReadFloatTifGrid(g_basicConfig->GetFAM()); + } + if (!g_FAM) { + ERROR_LOG("Failed to load FAM!"); + return false; + } + if (!g_DEM->IsSpatialMatch(g_FAM)) { + ERROR_LOG("The spatial characteristics of the DEM and FAM differ!"); + return false; + } + + if (g_basicConfig->IsESRIDDM()) { + if (CheckESRIDDM()) { + ReclassifyDDM(); + } else { + ERROR_LOG("Was expecting an ESRI Drainage Direction Map and got invalid values!"); + return false; + } + } else { + if (!CheckSimpleDDM()) { + ERROR_LOG("Was expecting a simple Drainage Direction Map and got invalid values!"); + return false; + } + } + + + + FixFAM(); + + return true; +} + +void FreeBasicGridsData() { + if (g_DEM && g_DEM->data) { + for (long i = 0; i < g_DEM->numRows; i++) { + delete [] g_DEM->data[i]; + } + delete [] g_DEM->data; + g_DEM->data = NULL; + } + + if (g_DDM && g_DDM->data) { + for (long i = 0; i < g_DDM->numRows; i++) { + delete [] g_DDM->data[i]; + } + delete [] g_DDM->data; + g_DDM->data = NULL; + } + + if (g_FAM && g_FAM->data) { + for (long i = 0; i < g_FAM->numRows; i++) { + delete [] g_FAM->data[i]; + } + delete [] g_FAM->data; + g_FAM->data = NULL; + } + +} + +void FindIndBasins(float left, float right, float top, float bottom) { + + long maxX = 0; + long minX = LONG_MAX; + long maxY = 0; + long minY = LONG_MAX; + int totalGauges = 0; + + FloatGrid maskGrid; + maskGrid.numCols = g_DEM->numCols; + maskGrid.numRows = g_DEM->numRows; + maskGrid.extent.top = g_DEM->extent.top; + maskGrid.extent.bottom = g_DEM->extent.bottom; + maskGrid.extent.left = g_DEM->extent.left; + maskGrid.extent.right = g_DEM->extent.right; + maskGrid.cellSize = g_DEM->cellSize; + maskGrid.noData = -9999.0; + maskGrid.data = new float*[maskGrid.numRows]; + for (long i = 0; i < maskGrid.numRows; i++) { + maskGrid.data[i] = new float[maskGrid.numCols]; + for (long j = 0; j < maskGrid.numCols; j++) { + maskGrid.data[i][j] = maskGrid.noData; + } + } + + + printf("Geographic is %f, %f and %f, %f\n", left, right, top, bottom); + g_Projection->ReprojectPoint(left, bottom, &left, &bottom); + g_Projection->ReprojectPoint(right, top, &right, &top); + printf("Projected is %f, %f and %f, %f\n", left, right, top, bottom); + + GridLoc loc1, loc2, locN; + if (!g_FAM->GetGridLoc(left, bottom, &loc1)) { + loc1.x = 0; + loc1.y = g_FAM->numRows; + } + if (!g_FAM->GetGridLoc(right, top, &loc2)) { + loc2.x = g_FAM->numCols; + loc2.y = 0; + } + + maxX = g_FAM->numCols; //loc2.x; + minX = 0;//loc1.x; + maxY = g_FAM->numRows; //loc1.y; + minY = 0; //loc2.y; + + printf("Min x %li, max x %li, min y %li, max y %li\n", minX, maxX, minY, maxY); + + std::list<FAMSearch *> gridCells; + std::stack<GridLoc *> walkNodes; + std::vector<std::list<FAMSearch *>::iterator> gcItrs; + + int totalElements = g_DEM->numCols * g_DEM->numRows; + printf("Total elements in gcItrs is %i\n", totalElements); + gcItrs.resize(totalElements); + for (long e = 0; e < totalElements; e++) { + gcItrs[e] = gridCells.end(); + } + + for (long row = minY; row < maxY; row++) { + for (long col = minX; col < maxX; col++) { + long index = row * g_DEM->numCols + col; + if (g_DEM->data[row][col] == g_DEM->noData || g_FAM->data[row][col] == g_FAM->noData) { + gcItrs[index] = gridCells.end(); + continue; + } + FAMSearch *fs = new FAMSearch; + fs->x = col; + fs->y = row; + fs->fa = g_FAM->data[row][col]; + fs->used = false; + gridCells.push_front(fs); + gcItrs[index] = gridCells.begin(); + } + } + + gridCells.sort(SortByFlowAccumFS); + FILE *test = fopen("basin_new.txt", "w"); + std::vector<long> gridIndices; + + for (FAMSearch *currentFS = gridCells.front(); currentFS != NULL; currentFS = gridCells.front()) { + + + if (gridCells.begin() == gridCells.end()) { + break; + } + + GridLoc *cCell = new GridLoc; + cCell->x = currentFS->x; + cCell->y = currentFS->y; + maskGrid.data[cCell->y][cCell->x] = totalGauges; + fprintf(test, "[Gauge %i] cellx=%li celly=%li outputts=false #Num Cells = %f\n", totalGauges, cCell->x, cCell->y, g_FAM->data[cCell->y][cCell->x]); + printf("Gauge %i cellx=%li celly=%li basinarea=%f\n", totalGauges, cCell->x, cCell->y, g_FAM->data[cCell->y][cCell->x]); + totalGauges++; + + walkNodes.push(cCell); + size_t index = cCell->y * g_DEM->numCols + cCell->x; + if (gcItrs[index] != gridCells.end()) { + gridCells.erase(gcItrs[index]); + gcItrs[index] = gridCells.end(); + } else { + printf("WTF!!!!\n"); + } + + while (!walkNodes.empty()) { + cCell = walkNodes.top(); + walkNodes.pop(); + + maskGrid.data[cCell->y][cCell->x] = totalGauges - 1.0; + + for (int i = 0; i < FLOW_QTY; i++) { + if (TestUpstream(cCell->x, cCell->y, (FLOW_DIR)i, &locN)) { + GridLoc *nextN = new GridLoc; + nextN->x = locN.x; + nextN->y = locN.y; + size_t index = nextN->y * g_DEM->numCols + nextN->x; + if (index >= 0 && index < gcItrs.size() && g_DEM->data[nextN->y][nextN->x] != g_DEM->noData && g_FAM->data[nextN->y][nextN->x] != g_FAM->noData) { + //printf("%i %i %i %i %i %i %i\n", index, nextN->y, nextN->x, g_FAM->data[nextN->y][nextN->x], minY, minX, maxX); + if (gcItrs[index] != gridCells.end()) { + gridCells.erase(gcItrs[index]); + } + gcItrs[index] = gridCells.end(); + walkNodes.push(nextN); + } else { + //printf("Hmm %i (%f, %f, %f)\n", index, g_DEM->data[nextN->y][nextN->x], g_FAM->data[nextN->y][nextN->x], g_DDM->data[nextN->y][nextN->x]); + delete nextN; + } + } + } + + delete cCell; + } + + } + + fprintf(test, "[Basin 0]\n"); + for (int i = 0; i < totalGauges; i++) { + fprintf(test, "gauge=%i ", i); + } + fprintf(test, "\n"); + fclose(test); + + WriteFloatTifGrid("maskgrid.tif", &maskGrid); +} + +void ClipBasicGrids(long x, long y, long search, const char *output) { + + long maxX = 0; + long minX = LONG_MAX; + long maxY = 0; + long minY = LONG_MAX; + + GridLoc loc; + loc.x = x; + loc.y = y; + + maxX = loc.x + search; + minX = loc.x - search; + maxY = loc.y + search; + minY = loc.y - search; + + FindIndBasins(-124.73, -66.95, 50.00, 24.5); + //FindIndBasins(-84.84, -67.26, 44.17, 35.76); + + printf("Search box is %ld, %ld, %ld, %ld, %ld, %ld\n", minX, maxX, minY, maxY, x, y); + + long ncols = maxX - minX; + long nrows = maxY - minY; + + LongGrid grid; + RefLoc ll, ur; + + // Initialize everything in the new grid + g_DEM->GetRefLoc(minX, maxY, &ll); + g_DEM->GetRefLoc(maxX, minY, &ur); + + grid.extent.left = ll.x; + grid.extent.bottom = ll.y; + grid.extent.right = ur.x; + grid.extent.top = ur.y; + grid.numCols = ncols; + grid.numRows = nrows; + grid.cellSize = g_DEM->cellSize; + grid.noData = -9999; //g_DEM->noData; + + grid.data = new long*[grid.numRows]; + for (long i = 0; i < grid.numRows; i++) { + grid.data[i] = new long[grid.numCols]; + } + + // Grid is setup! Copy over FAM to new grid + for (long row = minY; row < maxY; row++) { + for (long col = minX; col < maxX; col++) { + grid.data[row - minY][col - minX] = g_FAM->data[row][col]; + } + } + + grid.data[loc.y - minY][loc.x - minX] = -1; + + char buffer[255]; + sprintf(buffer, "%s/%s.clip", output, strrchr(g_basicConfig->GetFAM(), '/')); + WriteLongAscGrid(buffer, &grid); + +} + +void ClipBasicGrids(BasinConfigSection *basin, std::vector<GridNode> *nodes, const char *name, const char *output) { + + FixFlowDir(basin, nodes); + + std::vector<GaugeConfigSection *> *gauges = basin->GetGauges(); + + long maxX = 0; + long minX = LONG_MAX; + long maxY = 0; + long minY = LONG_MAX; + + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + if (!node->gauge) { + continue; + } + if (node->x > maxX) { + maxX = node->x; + } + if (node->x < minX) { + minX = node->x; + } + if (node->y > maxY) { + maxY = node->y; + } + if (node->y < minY) { + minY = node->y; + } + } + + // We want to be inclusive + maxX++; + maxY++; + + //printf("Clipping %zd nodes, %lu maxx, %lu minx, %lu maxy, %lu miny\n", nodes->size(), maxX, minX, maxY, minY); + + long ncols = maxX - minX; + long nrows = maxY - minY; + + FloatGrid grid; + RefLoc ll, ur; + + // Initialize everything in the new grid + g_DEM->GetRefLoc(minX, maxY, &ll); + g_DEM->GetRefLoc(maxX, minY, &ur); + + grid.extent.left = ll.x; + grid.extent.bottom = ll.y; + grid.extent.right = ur.x; + grid.extent.top = ur.y; + grid.numCols = ncols; + grid.numRows = nrows; + grid.cellSize = g_DEM->cellSize; + grid.noData = -9999; //g_DEM->noData; + + grid.data = new float*[grid.numRows]; + for (long i = 0; i < grid.numRows; i++) { + grid.data[i] = new float[grid.numCols]; + } + + // Grid is setup! Copy over no data values everywhere + for (long row = 0; row < nrows; row++) { + for (long col = 0; col < ncols; col++) { + grid.data[row][col] = grid.noData; + } + } + + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + if (!node->gauge) { + continue; + } + for (size_t i = 0; i < gauges->size(); i++) { + GaugeConfigSection *gauge = gauges->at(i); + if (gauge->GetGridNodeIndex() == (long)node->index) { + printf("[gauge %s] cellx=%li celly=%li\n", gauge->GetName(), node->x - minX, node->y - minY); + break; + } + } + grid.data[node->y - minY][node->x - minX] = g_DEM->data[node->y][node->x]; + } + + char buffer[255]; + sprintf(buffer, "%s/%s.%s", output, strrchr(g_basicConfig->GetDEM(), '/'), name); + WriteFloatTifGrid(buffer, &grid); + + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + if (!node->gauge) { + continue; + } + grid.data[node->y - minY][node->x - minX] = g_DDM->data[node->y][node->x]; + } + + sprintf(buffer, "%s/%s.%s", output, strrchr(g_basicConfig->GetDDM(), '/'), name); + WriteFloatTifGrid(buffer, &grid); + + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + if (!node->gauge) { + continue; + } + grid.data[node->y - minY][node->x - minX] = g_FAM->data[node->y][node->x]; + } + + sprintf(buffer, "%s/%s.%s", output, strrchr(g_basicConfig->GetFAM(), '/'), name); + WriteFloatTifGrid(buffer, &grid); + +} + +void FixFlowDir(BasinConfigSection *basin, std::vector<GridNode> *nodes) { + std::vector<GaugeConfigSection *> *gauges = basin->GetGauges(); + GaugeConfigSection *gauge = gauges->at(0); + int maxDist = 20000.0 / g_Projection->GetLen(gauge->GetLon(), gauge->GetLat(), FLOW_NORTH); //3000; + if (maxDist < 2) { + maxDist = 2; + } + + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + if (node->downStreamNode == INVALID_DOWNSTREAM_NODE) { + continue; + } + GridNode *dsNode = &(nodes->at(node->downStreamNode)); + if (g_DEM->data[node->y][node->x] != g_DEM->data[dsNode->y][dsNode->x]) { + continue; + } + long maxFlow = g_FAM->data[dsNode->y][dsNode->x] * 10000; //maxDist; + FLOW_DIR flowDir = (FLOW_DIR)g_DDM->data[node->y][node->x]; + long testX, testY; + float minDist = powf(maxDist, 2.0) + powf(maxDist, 2.0); + for (int dist = 1; dist < maxDist; dist++) { + testX = node->x + 1 * dist; + testY = node->y; + if (testX < g_FAM->numCols && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_EAST; + } + } + + testX = node->x + 1 * dist; + testY = node->y - 1 * dist; + if (testX < g_FAM->numCols && testY >= 0 && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_NORTHEAST; + } + } + + testX = node->x; + testY = node->y - 1 * dist; + if (testY >= 0 && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_NORTH; + } + } + + testX = node->x - 1 * dist; + testY = node->y - 1 * dist; + if (testX >= 0 && testY >= 0 && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_NORTHWEST; + } + } + + testX = node->x - 1 * dist; + testY = node->y; + if (testX >= 0 && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_WEST; + } + } + + testX = node->x - 1 * dist; + testY = node->y + 1 * dist; + if (testX >= 0 && testY < g_FAM->numRows && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_SOUTHWEST; + } + } + + testX = node->x; + testY = node->y + 1 * dist; + if (testY < g_FAM->numRows && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_SOUTH; + } + } + + testX = node->x + 1 * dist; + testY = node->y + 1 * dist; + if (testX < g_FAM->numCols && testY < g_FAM->numRows && g_FAM->data[testY][testX] != g_FAM->noData && g_FAM->data[testY][testX] > maxFlow && g_DEM->data[node->y][node->x] == g_DEM->data[testY][testX]) { + float thisDist = powf(testY - node->y, 2.0) + powf(testX - node->x, 2.0); + if (thisDist < minDist) { + minDist = thisDist; + maxFlow = g_FAM->data[testY][testX]; + flowDir = FLOW_SOUTHEAST; + } + } + + + } + if (flowDir != g_DDM->data[node->y][node->x]) { + printf("Old dir %f, new dir %i\n", g_DDM->data[node->y][node->x], flowDir); + g_DDM->data[node->y][node->x] = (float)(flowDir); + } + } + +} + +void CarveBasin(BasinConfigSection *basin, std::vector<GridNode> *nodes, std::map<GaugeConfigSection *, float *> *inParamSettings, std::map<GaugeConfigSection *, float *> *outParamSettings, GaugeMap *gaugeMap, float *defaultParams, std::map<GaugeConfigSection *, float *> *inRouteParamSettings, std::map<GaugeConfigSection *, float *> *outRouteParamSettings, float *defaultRouteParams, std::map<GaugeConfigSection *, float *> *inSnowParamSettings, std::map<GaugeConfigSection *, float *> *outSnowParamSettings, float *defaultSnowParams, std::map<GaugeConfigSection *, float *> *inInundationParamSettings, std::map<GaugeConfigSection *, float *> *outInundationParamSettings, float *defaultInundationParams) { + + std::vector<GaugeConfigSection *> *gauges = basin->GetGauges(); + std::stack<GridNode *> walkNodes; + size_t currentNode = 0; + size_t totalAccum = 0; + GridLoc nextNode; + + // Figure out where each gauge is at and get the flow accumulation from the grid for it. + // Also resets the used flag to false + for (std::vector<GaugeConfigSection *>::iterator itr = gauges->begin(); itr != gauges->end(); ) { + + GaugeConfigSection *gauge = *(itr); + GridLoc *loc = gauge->GetGridLoc(); + if (gauge->NeedsProjecting()) { + if (!g_FAM->GetGridLoc(gauge->GetLon(), gauge->GetLat(), loc)) { + WARNING_LOGF("Gauge %s is outside the basic grid domain!\n", gauge->GetName()); + itr = gauges->erase(itr); + continue; + } + } else { + RefLoc ref; + g_FAM->GetRefLoc(loc->x, loc->y, &ref); + gauge->SetLat(ref.y); + gauge->SetLon(ref.x); + } + float areaFactor = 1.0 / g_Projection->GetArea(gauge->GetLon(), gauge->GetLat()); + int maxDist = 20000.0 / g_Projection->GetLen(gauge->GetLon(), gauge->GetLat(), FLOW_NORTH); //3000; + if (maxDist < 2) { + maxDist = 2; + } + INFO_LOGF("Max gauge search distance is %i", maxDist); + if (gauge->HasObsFlowAccum()) { + GridLoc minLoc; + float testError, minError = pow((float)(g_FAM->data[loc->y][loc->x]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + minLoc.x = loc->x; + minLoc.y = loc->y; + long testX, testY; + for (int dist = 1; dist < maxDist; dist++) { + testX = loc->x + 1 * dist; + testY = loc->y; + if (testX < g_FAM->numCols && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + + testX = loc->x + 1 * dist; + testY = loc->y + 1 * dist; + if (testX < g_FAM->numCols && testY < g_FAM->numRows && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + + testX = loc->x; + testY = loc->y + 1 * dist; + if (testY < g_FAM->numRows && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + + testX = loc->x - 1 * dist; + testY = loc->y + 1 * dist; + if (testX > 0 && testY < g_FAM->numRows && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + + testX = loc->x - 1 * dist; + testY = loc->y; + if (testX > 0 && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + + testX = loc->x - 1 * dist; + testY = loc->y - 1 * dist; + if (testX > 0 && testY > 0 && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + + testX = loc->x; + testY = loc->y - 1 * dist; + if (testY > 0 && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + + testX = loc->x + 1 * dist; + testY = loc->y - 1 * dist; + if (testX < g_FAM->numCols && testY > 0 && g_FAM->data[testY][testX] != g_FAM->noData) { + testError = pow((float)(g_FAM->data[testY][testX]) - gauge->GetObsFlowAccum()*areaFactor, 2.0); + if (minError > testError) { + minError = testError; + minLoc.x = testX; + minLoc.y = testY; + } + } + } + + loc->x = minLoc.x; + loc->y = minLoc.y; + RefLoc ref; + g_FAM->GetRefLoc(loc->x, loc->y, &ref); + gauge->SetLat(ref.y); + gauge->SetLon(ref.x); + } + gauge->SetFlowAccum(g_FAM->data[loc->y][loc->x]); + gauge->SetUsed(false); + INFO_LOGF("Gauge %s (%f, %f; %ld, %ld): FAM %ld", gauge->GetName(), gauge->GetLat(), gauge->GetLon(), loc->y, loc->x, gauge->GetFlowAccum()); + itr++; + } + + // Sort the gauges into descending order based on flow accumulation + // This helps us ensure that the independent gauges are the ones at the basin outlets + std::sort(gauges->begin(), gauges->end(), SortByFlowAccum); + + std::map<unsigned long, GaugeConfigSection *> gaugeCMap; + for (std::vector<GaugeConfigSection *>::iterator itr = gauges->begin(); itr != gauges->end(); ) { + GaugeConfigSection *gauge = *(itr); + GridLoc *loc = gauge->GetGridLoc(); + unsigned long index = loc->y * g_DEM->numCols + loc->x; + std::map<unsigned long, GaugeConfigSection *>::iterator itrM = gaugeCMap.find(index); + if (itrM == gaugeCMap.end()) { + gaugeCMap.insert(std::pair<unsigned long, GaugeConfigSection*>(index, gauge)); + itr++; + } else { + WARNING_LOGF("Duplicate gauge!! %s\n", gauge->GetName()); + itr = gauges->erase(itr); + } + } + + gaugeMap->Initialize(gauges); + + + // Here we compute which grid cells & gauges are upstream of our independent gauges + for (GaugeConfigSection *currentGauge = (*gauges)[0]; currentGauge != NULL; currentGauge = NextUnusedGauge(gauges)) { + + std::map<GaugeConfigSection *, float *>::iterator pitr = inParamSettings->find(currentGauge); + if (pitr == inParamSettings->end() && !defaultParams) { + ERROR_LOGF("Independent basin \"%s\" lacks a water balance parameter set!", currentGauge->GetName()); + return; + } + + if (pitr == inParamSettings->end()) { + outParamSettings->insert(std::pair<GaugeConfigSection *, float *>(currentGauge, defaultParams)); + } else { + outParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + + if (inRouteParamSettings) { + pitr = inRouteParamSettings->find(currentGauge); + if (pitr == inRouteParamSettings->end() && !defaultRouteParams) { + ERROR_LOGF("Independent basin \"%s\" lacks a routing parameter set!", currentGauge->GetName()); + return; + } + + if (pitr == inRouteParamSettings->end()) { + outRouteParamSettings->insert(std::pair<GaugeConfigSection *, float *>(currentGauge, defaultRouteParams)); + } else { + outRouteParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + + } + + if (inSnowParamSettings) { + pitr = inSnowParamSettings->find(currentGauge); + if (pitr == inSnowParamSettings->end() && !defaultSnowParams) { + ERROR_LOGF("Independent basin \"%s\" lacks a snow parameter set!", currentGauge->GetName()); + return; + } + + if (pitr == inSnowParamSettings->end()) { + outSnowParamSettings->insert(std::pair<GaugeConfigSection *, float *>(currentGauge, defaultSnowParams)); + } else { + outSnowParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + + } + + if (inInundationParamSettings) { + pitr = inInundationParamSettings->find(currentGauge); + if (pitr == inInundationParamSettings->end() && !defaultInundationParams) { + ERROR_LOGF("Independent basin \"%s\" lacks a inundation parameter set!", currentGauge->GetName()); + return; + } + + if (pitr == inInundationParamSettings->end()) { + outInundationParamSettings->insert(std::pair<GaugeConfigSection *, float *>(currentGauge, defaultInundationParams)); + } else { + outInundationParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + + } + + if (g_basicConfig->IsSelfFAM()) { + totalAccum += currentGauge->GetFlowAccum(); + } else { + totalAccum += (currentGauge->GetFlowAccum() + 1); + } + nodes->resize(totalAccum); + GridNode *currentN = &(*nodes)[currentNode]; + + //Setup the initial node for initiating the search for upstream nodes + currentN->index = currentNode; + currentNode++; + currentN->x = currentGauge->GetGridLoc()->x; + currentN->y = currentGauge->GetGridLoc()->y; + g_DEM->GetRefLoc(currentN->x, currentN->y, ¤tN->refLoc); + if (g_DEM->data[currentN->y][currentN->x] == g_DEM->noData || g_FAM->data[currentN->y][currentN->x] == g_FAM->noData || g_FAM->data[currentN->y][currentN->x] < 0) { + ERROR_LOGF("Gauge \"%s\" is located in a no data grid cell!", currentGauge->GetName()); + return; + } + currentN->downStreamNode = INVALID_DOWNSTREAM_NODE; + long outsideHeight = 0; + if (GetDownstreamHeight(currentN->x, currentN->y, &outsideHeight)) { + currentN->horLen = g_Projection->GetLen(currentN->refLoc.x, currentN->refLoc.y, (FLOW_DIR)g_DDM->data[currentN->y][currentN->x]); + float DEMDiff = g_DEM->data[currentN->y][currentN->x] - outsideHeight; + currentN->slope = ((DEMDiff < 1.0) ? 1.0 : DEMDiff) / currentN->horLen; + } else { + currentN->horLen = g_Projection->GetLen(currentN->refLoc.x, currentN->refLoc.y, FLOW_NORTH); // We assume a horizontal length because we know nothing further + currentN->slope = 1.0 / currentN->horLen; // We assume a difference in height of 1 meter because we know nothing else + } + currentN->area = g_Projection->GetArea(currentN->refLoc.x, currentN->refLoc.y); + currentN->contribArea = currentN->area; + currentN->fac = g_FAM->data[currentN->y][currentN->x]; + walkNodes.push(currentN); + + while (!walkNodes.empty()) { + + //Get the next node to check off the stack + currentN = walkNodes.top(); + walkNodes.pop(); + + //Store the previous gauge + GaugeConfigSection *prevGauge = currentN->gauge; + + //Is this node actually a gauge? + GaugeConfigSection *nodeGauge = FindGauge(&gaugeCMap, currentN); + bool keepGoing = true; + if (nodeGauge) { + nodeGauge->SetGridNodeIndex(currentN->index); + currentN->gauge = nodeGauge; + nodeGauge->SetUsed(true); + keepGoing = nodeGauge->ContinueUpstream(); + + + // Add this to the gauge map which allows us to figure out upstream gauges & contributions + gaugeMap->AddUpstreamGauge(prevGauge, nodeGauge); + + //We fill in outParamSettings for the new gauge here + //Since it is not required that inParamSettings contain parameters for every gauge in the basin we will in parameters from downstream gauges upstream + pitr = inParamSettings->find(nodeGauge); + if (pitr == inParamSettings->end()) { + pitr = outParamSettings->find(prevGauge); + outParamSettings->insert(std::pair<GaugeConfigSection *, float *>(nodeGauge, pitr->second)); + } else { + outParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + if (inRouteParamSettings) { + pitr = inRouteParamSettings->find(nodeGauge); + if (pitr == inRouteParamSettings->end()) { + pitr = outRouteParamSettings->find(prevGauge); + outRouteParamSettings->insert(std::pair<GaugeConfigSection *, float *>(nodeGauge, pitr->second)); + } else { + outRouteParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + } + + if (inSnowParamSettings) { + pitr = inSnowParamSettings->find(nodeGauge); + if (pitr == inSnowParamSettings->end()) { + pitr = outSnowParamSettings->find(prevGauge); + outSnowParamSettings->insert(std::pair<GaugeConfigSection *, float *>(nodeGauge, pitr->second)); + } else { + outSnowParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + } + + if (inInundationParamSettings) { + pitr = inInundationParamSettings->find(nodeGauge); + if (pitr == inInundationParamSettings->end()) { + pitr = outInundationParamSettings->find(prevGauge); + outInundationParamSettings->insert(std::pair<GaugeConfigSection *, float *>(nodeGauge, pitr->second)); + } else { + outInundationParamSettings->insert(std::pair<GaugeConfigSection *, float *>(pitr->first, pitr->second)); + } + } + + } + + long currentNDEM = g_DEM->data[currentN->y][currentN->x]; + + //Lets figure out what flows into this node + //We compute slope here too! + if (keepGoing) { + for (int i = 1; i < FLOW_QTY; i++) { + if (TestUpstream(currentN, (FLOW_DIR)i, &nextNode)) { + GridNode *nextN = &(*nodes)[currentNode]; + nextN->index = currentNode; + currentNode++; + nextN->x = nextNode.x; + nextN->y = nextNode.y; + nextN->downStreamNode = currentN->index; + nextN->gauge = currentN->gauge; + nextN->fac = g_FAM->data[nextN->y][nextN->x]; + + //Calculate slope! + long nextNDEM = g_DEM->data[nextN->y][nextN->x]; + float DEMDiff = (float)(nextNDEM - currentNDEM); // Upstream (higher elevation) minus downstream (lower elevation) + g_DEM->GetRefLoc(nextN->x, nextN->y, &nextN->refLoc); + nextN->horLen = g_Projection->GetLen(nextN->refLoc.x, nextN->refLoc.y, (FLOW_DIR)i); + nextN->slope = ((DEMDiff < 1.0) ? 1.0 : DEMDiff) / nextN->horLen; + nextN->area = g_Projection->GetArea(nextN->refLoc.x, nextN->refLoc.y); + nextN->contribArea = nextN->area; + //printf("Pushing node %i %i (%i, %i) from %i %i (%i, %i) %i %i\n", nextN->x, nextN->y, g_DDM->data[nextN->y][nextN->x], g_FAM->data[nextN->y][nextN->x], currentN->x, currentN->y, g_DDM->data[currentN->y][currentN->x], g_FAM->data[currentN->y][currentN->x], currentNode, nodes->size()); + walkNodes.push(nextN); + } + } + } + + } + + INFO_LOGF("Walked %lu (out of %lu) nodes for %s!", (unsigned long)currentNode, (unsigned long)totalAccum, currentGauge->GetName()); + } + + nodes->resize(currentNode); + + for (long i = nodes->size() - 1; i >= 0; i--) { + GridNode *node = &nodes->at(i); + if (node->downStreamNode != INVALID_DOWNSTREAM_NODE) { + nodes->at(node->downStreamNode).contribArea += node->contribArea; + } + } + + + /*FILE *fp = fopen("gauge_data.txt", "w"); + FILE *fp2 = fopen("basin_data.txt", "w"); + for (std::vector<GaugeConfigSection *>::iterator itr = gauges->begin(); itr != gauges->end(); itr++ ) { + GaugeConfigSection *gauge = *(itr); + GridLoc *loc = gauge->GetGridLoc(); + fprintf(fp, "[Gauge %s] cellx=%li celly=%li basinarea=%f %ld %li wantco=true outputts=false\n", gauge->GetName(), loc->x, loc->y, nodes->at(gauge->GetGridNodeIndex()).contribArea, gauge->GetFlowAccum(), gauge->GetGridNodeIndex()); + fprintf(fp2, "gauge=%s\n", gauge->GetName()); + } + fclose(fp); + fclose(fp2); + */ +} + +bool GetDownstreamHeight(long x, long y, long *outsideHeight) { + long nextX = x; + long nextY = y; + + switch ((int)(g_DDM->data[y][x])) { + case FLOW_NORTH: + nextY--; + break; + case FLOW_NORTHEAST: + nextY--; + nextX++; + break; + case FLOW_EAST: + nextX++; + break; + case FLOW_SOUTHEAST: + nextY++; + nextX++; + break; + case FLOW_SOUTH: + nextY++; + break; + case FLOW_SOUTHWEST: + nextY++; + nextX--; + break; + case FLOW_WEST: + nextX--; + break; + case FLOW_NORTHWEST: + nextX--; + nextY--; + break; + default: + return false; + } + + if (nextX >= 0 && nextY >= 0 && nextX < g_DEM->numCols && nextY < g_DEM->numRows && g_DEM->data[nextY][nextX] != g_DEM->noData) { + *outsideHeight = g_DEM->data[nextY][nextX]; + return true; + } + + return false; +} + +bool TestUpstream(GridNode *node, FLOW_DIR dir, GridLoc *loc) { + return TestUpstream(node->x, node->y, dir, loc); +} + +bool TestUpstream(long nextX, long nextY, FLOW_DIR dir, GridLoc *loc) { + FLOW_DIR wantDir; + + //unsigned long currentFAC = g_FAM->data[nextY][nextX]; + + switch (dir) { + case FLOW_NORTH: + nextY--; + wantDir = FLOW_SOUTH; + break; + case FLOW_NORTHEAST: + nextY--; + nextX++; + wantDir = FLOW_SOUTHWEST; + break; + case FLOW_EAST: + nextX++; + wantDir = FLOW_WEST; + break; + case FLOW_SOUTHEAST: + nextY++; + nextX++; + wantDir = FLOW_NORTHWEST; + break; + case FLOW_SOUTH: + nextY++; + wantDir = FLOW_NORTH; + break; + case FLOW_SOUTHWEST: + nextY++; + nextX--; + wantDir = FLOW_NORTHEAST; + break; + case FLOW_WEST: + nextX--; + wantDir = FLOW_EAST; + break; + case FLOW_NORTHWEST: + nextX--; + nextY--; + wantDir = FLOW_SOUTHEAST; + break; + default: + return false; + } + + if (nextX >= 0 && nextY >= 0 && nextX < g_DDM->numCols && nextY < g_DDM->numRows && g_DDM->data[nextY][nextX] == wantDir) { // && g_FAM->data[nextY][nextX] <= currentFAC) { + loc->x = nextX; + loc->y = nextY; + return true; + } + + return false; +} + +bool TestUpstreamBroken(long nextX, long nextY, FLOW_DIR dir, GridLoc *loc) { + FLOW_DIR wantDir; + + unsigned long currentFAC = g_FAM->data[nextY][nextX]; + + switch (dir) { + case FLOW_NORTH: + nextY--; + wantDir = FLOW_SOUTH; + break; + case FLOW_NORTHEAST: + nextY--; + nextX++; + wantDir = FLOW_SOUTHWEST; + break; + case FLOW_EAST: + nextX++; + wantDir = FLOW_WEST; + break; + case FLOW_SOUTHEAST: + nextY++; + nextX++; + wantDir = FLOW_NORTHWEST; + break; + case FLOW_SOUTH: + nextY++; + wantDir = FLOW_NORTH; + break; + case FLOW_SOUTHWEST: + nextY++; + nextX--; + wantDir = FLOW_NORTHEAST; + break; + case FLOW_WEST: + nextX--; + wantDir = FLOW_EAST; + break; + case FLOW_NORTHWEST: + nextX--; + nextY--; + wantDir = FLOW_SOUTHEAST; + break; + default: + return false; + } + + if (nextX >= 0 && nextY >= 0 && nextX < g_DDM->numCols && nextY < g_DDM->numRows && g_DDM->data[nextY][nextX] == wantDir && g_FAM->data[nextY][nextX] > currentFAC) { + loc->x = nextX; + loc->y = nextY; + return true; + } + + return false; +} + +GaugeConfigSection *FindGauge(std::map<unsigned long, GaugeConfigSection *> *gauges, GridNode *node) { + + unsigned long index = node->y * g_DEM->numCols + node->x; + + std::map<unsigned long, GaugeConfigSection *>::iterator itr = gauges->find(index); + + if (itr == gauges->end()) { + return NULL; + } else { + return itr->second; + } + + /*for (std::vector<GaugeConfigSection *>::iterator itr = gauges->begin(); itr != gauges->end(); itr++) { + + GaugeConfigSection *gauge = *(itr); + GridLoc *loc = gauge->GetGridLoc(); + if (loc->x == node->x && loc->y == node->y) { + printf("Next gauge is %s\n", gauge->GetName()); + return gauge; + } + } + + return NULL;*/ + +} + +GaugeConfigSection *NextUnusedGauge(std::vector<GaugeConfigSection *> *gauges) { + + for (std::vector<GaugeConfigSection *>::iterator itr = gauges->begin(); itr != gauges->end(); itr++) { + + GaugeConfigSection *gauge = *(itr); + if (!gauge->GetUsed()) { + return gauge; + } + } + + return NULL; + +} + +bool SortByFlowAccum(GaugeConfigSection *d1, GaugeConfigSection *d2) { + return d1->GetFlowAccum() > d2->GetFlowAccum(); +} + +bool SortByFlowAccumFS(FAMSearch *fs1, FAMSearch *fs2) { + return fs1->fa > fs2->fa; +} + +bool CheckESRIDDM() { + for (long row = 0; row < g_DDM->numRows; row++) { + for (long col = 0; col < g_DDM->numCols; col++) { + if (g_DDM->data[row][col] == g_DDM->noData) { + continue; + } + switch ((int)(g_DDM->data[row][col])) { + case 0: + g_DDM->data[row][col] = g_DDM->noData; + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + continue; + default: + ERROR_LOGF("Bad DDM value %i at (%li, %li) %f", (int)(g_DDM->data[row][col]), col, row, g_DDM->noData); + return false; + } + } + } + return true; +} + +bool CheckSimpleDDM() { + for (long row = 0; row < g_DDM->numRows; row++) { + for (long col = 0; col < g_DDM->numCols; col++) { + if (g_DDM->data[row][col] == g_DDM->noData) { + continue; + } + switch ((int)(g_DDM->data[row][col])) { + case 0: + g_DDM->data[row][col] = g_DDM->noData; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + continue; + default: + return false; + } + } + } + return true; +} + +void ReclassifyDDM() { + + for (long row = 0; row < g_DDM->numRows; row++) { + for (long col = 0; col < g_DDM->numCols; col++) { + switch ((int)(g_DDM->data[row][col])) { + case 64: + g_DDM->data[row][col] = FLOW_NORTH; + break; + case 128: + g_DDM->data[row][col] = FLOW_NORTHEAST; + break; + case 1: + g_DDM->data[row][col] = FLOW_EAST; + break; + case 2: + g_DDM->data[row][col] = FLOW_SOUTHEAST; + break; + case 4: + g_DDM->data[row][col] = FLOW_SOUTH; + break; + case 8: + g_DDM->data[row][col] = FLOW_SOUTHWEST; + break; + case 16: + g_DDM->data[row][col] = FLOW_WEST; + break; + case 32: + g_DDM->data[row][col] = FLOW_NORTHWEST; + break; + } + } + } +} + +void FixFAM() { + GridLoc locN; + + for (long row = 0; row < g_DEM->numRows; row++) { + for (long col = 0; col < g_DEM->numCols; col++) { + if (g_DEM->data[row][col] == g_DEM->noData || g_FAM->data[row][col] == g_FAM->noData || g_DDM->data[row][col] == g_DDM->noData) { + g_DEM->data[row][col] = g_DEM->noData; + g_FAM->data[row][col] = g_FAM->noData; + g_DDM->data[row][col] = g_DDM->noData; + } + } + } + + return; + + for (long row = 0; row < g_FAM->numRows; row++) { + for (long col = 0; col < g_FAM->numCols; col++) { + if (g_FAM->data[row][col] != g_FAM->noData) { + for (int i = 1; i < FLOW_QTY; i++) { + if (TestUpstreamBroken(col, row, (FLOW_DIR)i, &locN)) { + INFO_LOGF("Adding %f cells to accumulation for cell (%li, %li; %f)\n", g_FAM->data[row][col], col, row, g_FAM->data[locN.y][locN.x]); + g_FAM->data[locN.y][locN.x] += g_FAM->data[row][col]; + if (!g_basicConfig->IsSelfFAM()) { + g_FAM->data[locN.y][locN.x] += 1; + } + } + } + } + } + + } +} + +int FlowsOut(long nextX, long nextY, FLOW_DIR dir, long currentHeight) { + + switch (dir) { + case FLOW_NORTH: + nextY--; + break; + case FLOW_NORTHEAST: + nextY--; + nextX++; + break; + case FLOW_EAST: + nextX++; + break; + case FLOW_SOUTHEAST: + nextY++; + nextX++; + break; + case FLOW_SOUTH: + nextY++; + break; + case FLOW_SOUTHWEST: + nextY++; + nextX--; + break; + case FLOW_WEST: + nextX--; + break; + case FLOW_NORTHWEST: + nextX--; + nextY--; + break; + default: + return 0; // Doesn't flow out + } + + if (nextX >= 0 && nextY >= 0 && nextX < g_DEM->numCols && nextY < g_DEM->numRows) { + if (g_DEM->data[nextY][nextX] == g_DEM->noData) { + return 1; // Flows out + } + + if (g_DEM->data[nextY][nextX] <= currentHeight) { + return 1; // Flows out + } + + if (g_DEM->data[nextY][nextX] > currentHeight) { + return 2; // Flows in, not out + + } + } + + return 0; // Doesn't flow out +} + +int FlowsIn(long nextX, long nextY, FLOW_DIR dir, long currentHeight, GridLoc *locIn, long maxSearch, GridLoc *locOut) { + + switch (dir) { + case FLOW_NORTH: + nextY--; + break; + case FLOW_NORTHEAST: + nextY--; + nextX++; + break; + case FLOW_EAST: + nextX++; + break; + case FLOW_SOUTHEAST: + nextY++; + nextX++; + break; + case FLOW_SOUTH: + nextY++; + break; + case FLOW_SOUTHWEST: + nextY++; + nextX--; + break; + case FLOW_WEST: + nextX--; + break; + case FLOW_NORTHWEST: + nextX--; + nextY--; + break; + default: + return 0; // Doesn't flow in + } + + if (nextX >= 0 && nextY >= 0 && nextX < g_DEM->numCols && nextY < g_DEM->numRows) { + if (labs(nextX - locIn->x) > maxSearch || labs(nextY - locIn->y) > maxSearch) { + return 0; // To Far away, don't consider it. + } + + if (g_DEM->data[nextY][nextX] == g_DEM->noData) { + return 0; // Doesn't flow in + } + + if (g_DEM->data[nextY][nextX] < currentHeight) { + return 0; // Flows out + } + + if (g_DEM->data[nextY][nextX] >= currentHeight) { + locOut->x = nextX; + locOut->y = nextY; + return 1; // Flows in + + } + } + + return 0; // Doesn't flow out +} + +void MakeBasic() { + int totalSinks = 0; + for (long row = 0; row < g_DEM->numRows; row++) { + for (long col = 0; col < g_DEM->numCols; col++) { + if (g_DEM->data[row][col] == g_DEM->noData) { + continue; + } + bool flowsIn = false; + bool flowsOut = false; + for (int i = 1; i < FLOW_QTY; i++) { + int result = FlowsOut(col, row, (FLOW_DIR)i, g_DEM->data[row][col]); + if (result == 2) { + flowsIn = true; + } else if (result == 1) { + flowsOut = true; + break; + } + } + if (!flowsOut && flowsIn) { + totalSinks++; + std::stack<GridNode *> walkNodes; + std::vector<GridNode *> sinkNodes; + GridNode *currentN = new GridNode; + GridLoc locIn, locOut; + locIn.x = col; + locIn.y = row; + currentN->x = col; + currentN->y = row; + currentN->fac = -1; + walkNodes.push(currentN); + while (!walkNodes.empty()) { + //Get the next node to check off the stack + currentN = walkNodes.top(); + walkNodes.pop(); + sinkNodes.push_back(currentN); + for (int i = 1; i < FLOW_QTY; i++) { + if (i == currentN->fac) { + continue; + } + if (FlowsIn(currentN->x, currentN->y, (FLOW_DIR)i, g_DEM->data[currentN->y][currentN->x], &locIn, 5, &locOut)) { + GridNode *newN = new GridNode; + newN->x = locOut.x; + newN->y = locOut.y; + newN->fac = reverseDir[i]; + } + } + } + + //if (col >= 1 && row >= 1) + //printf("Found inflow sink %i %i %i (%i %i %i %i %i %i %i %i)!\n", col, row, g_DEM->data[row][col], g_DEM->data[row-1][col-1], g_DEM->data[row-1][col], g_DEM->data[row-1][col+1], g_DEM->data[row][col-1], g_DEM->data[row][col+1], g_DEM->data[row+1][col-1], g_DEM->data[row+1][col], g_DEM->data[row+1][col+1]); + } + } + } + + printf("Total sinks %i", totalSinks); +} diff --git a/src/BasicGrids.h b/src/BasicGrids.h new file mode 100755 index 0000000..b1286f8 --- /dev/null +++ b/src/BasicGrids.h @@ -0,0 +1,27 @@ +#ifndef BASIC_GRIDS_H +#define BASIC_GRIDS_H + +#include <vector> +#include "BasinConfigSection.h" +#include "GaugeConfigSection.h" +#include "GridNode.h" +#include "Grid.h" +#include "Projection.h" +#include "GaugeMap.h" + +bool LoadBasicGrids(); +void FreeBasicGridsData(); +void ClipBasicGrids(long x, long y, long search, const char *output); +void ClipBasicGrids(BasinConfigSection *basin, std::vector<GridNode> *nodes, const char *name, const char *output); +void CarveBasin(BasinConfigSection *basin, std::vector<GridNode> *nodes, std::map<GaugeConfigSection *, float *> *inParamSettings, std::map<GaugeConfigSection *, float *> *outParamSettings, GaugeMap *gaugeMap, float *defaultParams, std::map<GaugeConfigSection *, float *> *inRouteParamSettings, std::map<GaugeConfigSection *, float *> *outRouteParamSettings, float *defaultRouteParams, std::map<GaugeConfigSection *, float *> *inSnowParamSettings, std::map<GaugeConfigSection *, float *> *outSnowParamSettings, float *defaultSnowParams, std::map<GaugeConfigSection *, float *> *inInundationParamSettings, std::map<GaugeConfigSection *, float *> *outInundationParamSettings, float *defaultInundationParams); +void MakeBasic(); +void ReclassifyDDM(); +bool CheckESRIDDM(); +bool CheckSimpleDDM(); + +extern FloatGrid *g_DEM; +extern FloatGrid *g_DDM; +extern FloatGrid *g_FAM; +extern Projection *g_Projection; + +#endif diff --git a/src/BasinConfigSection.cpp b/src/BasinConfigSection.cpp new file mode 100755 index 0000000..3cc7327 --- /dev/null +++ b/src/BasinConfigSection.cpp @@ -0,0 +1,67 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "BasinConfigSection.h" + +std::map<std::string, BasinConfigSection *> g_basinConfigs; + +BasinConfigSection::BasinConfigSection(char *newName) { + strcpy(name, newName); +} + +BasinConfigSection::~BasinConfigSection() { + +} + +CONFIG_SEC_RET BasinConfigSection::ProcessKeyValue(char *name, char *value) { + if (strcasecmp(name, "gauge") == 0) { + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in basin!", value); + return INVALID_RESULT; + } + if (IsDuplicateGauge(itr->second)) { + ERROR_LOGF("Duplicate gauge \"%s\" in basin!", value); + return INVALID_RESULT; + } + gauges.push_back(itr->second); + } else { + ERROR_LOGF("Unknown key value \"%s=%s\" in basin %s!", name, value, this->name); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +CONFIG_SEC_RET BasinConfigSection::ValidateSection() { + + if (gauges.size() == 0) { + ERROR_LOG("A basin was defined which contains no gauges!"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +bool BasinConfigSection::IsDuplicateGauge(GaugeConfigSection *gauge) { + + // Scan the vector for duplicates + for (std::vector<GaugeConfigSection *>::iterator itr = gauges.begin(); itr != gauges.end(); itr++) { + if (gauge == (*itr)) { + return true; + } + } + + // No duplicates found! + return false; +} + +bool BasinConfigSection::IsDuplicate(char *name) { + std::map<std::string, BasinConfigSection *>::iterator itr = g_basinConfigs.find(std::string(name)); + if (itr == g_basinConfigs.end()) { + return false; + } else { + return true; + } +} diff --git a/src/BasinConfigSection.h b/src/BasinConfigSection.h new file mode 100755 index 0000000..6341bb4 --- /dev/null +++ b/src/BasinConfigSection.h @@ -0,0 +1,32 @@ +#ifndef CONFIG_BASIN_SECTION_H +#define CONFIG_BASIN_SECTION_H + +#include <map> +#include <vector> +#include <string> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" + +class BasinConfigSection : public ConfigSection { + + public: + BasinConfigSection(char *newName); + ~BasinConfigSection(); + + char *GetName() { return name; } + std::vector<GaugeConfigSection *> *GetGauges() { return &gauges; } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name); + + private: + bool IsDuplicateGauge(GaugeConfigSection *gauge); + char name[CONFIG_MAX_LEN]; + std::vector<GaugeConfigSection *> gauges; +}; + +extern std::map<std::string, BasinConfigSection *> g_basinConfigs; + +#endif diff --git a/src/BifGrid.cpp b/src/BifGrid.cpp new file mode 100755 index 0000000..6efa022 --- /dev/null +++ b/src/BifGrid.cpp @@ -0,0 +1,68 @@ +#include <cstdio> +#include <fcntl.h> +#include "Messages.h" +#include "BifGrid.h" + +FloatGrid *ReadFloatBifGrid(char *file) { + + BifHeader header; + FloatGrid *grid = NULL; + FILE *fileH; + + fileH = fopen(file, "rb"); + if (fileH == NULL) { + return NULL; + } + + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_SEQUENTIAL); + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_WILLNEED); + //posix_fadvise(fileno(fileH), 0, 0, POSIX_FADV_NOREUSE); + + grid = new FloatGrid(); + + if (fread(&header, sizeof(BifHeader), 1, fileH) != 1) { + WARNING_LOGF("BIF file %s missing header", file); + fclose(fileH); + delete grid; + return NULL; + } + + grid->numCols = header.ncols; + grid->numRows = header.nrows; + grid->cellSize = header.cellsize; + grid->extent.bottom = header.yllcor; + grid->extent.left = header.xllcor; + + grid->data = new float*[grid->numRows](); + if (!grid->data) { + WARNING_LOGF("BIF file %s too large (out of memory) with %li rows", file, grid->numRows); + delete grid; + fclose(fileH); + return NULL; + } + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new float[grid->numCols]; + if (!grid->data[i]) { + WARNING_LOGF("BIF file %s too large (out of memory) with %li columns", file, grid->numCols); + delete grid; + fclose(fileH); + return NULL; + } + if (fread(grid->data[i], sizeof(float), grid->numCols, fileH) != (size_t)grid->numCols) { + WARNING_LOGF("BIF file %s corrupt?", file); + delete grid; + fclose(fileH); + return NULL; + } + } + + //Fill in the rest of the BoundingBox + grid->extent.top = grid->extent.bottom + grid->numRows*grid->cellSize; + grid->extent.right = grid->extent.left + grid->numCols*grid->cellSize; + + fclose(fileH); + + return grid; + + +} diff --git a/src/BifGrid.h b/src/BifGrid.h new file mode 100755 index 0000000..5cff219 --- /dev/null +++ b/src/BifGrid.h @@ -0,0 +1,21 @@ +#ifndef BIF_GRID_H +#define BIF_GRID_H + +#include "Grid.h" + +#pragma pack(push) +#pragma pack(1) +struct BifHeader { + int ncols; + int nrows; + float xllcor; + float yllcor; + float cellsize; + float nodata; + char empty[26]; +}; +#pragma pack(pop) + +FloatGrid *ReadFloatBifGrid(char *file); + +#endif diff --git a/src/BoundingBox.h b/src/BoundingBox.h new file mode 100755 index 0000000..1fdef1e --- /dev/null +++ b/src/BoundingBox.h @@ -0,0 +1,14 @@ +#ifndef BOUNDING_BOX_H +#define BOUNDING_BOX_H + +class BoundingBox { + + public: + float top; + float bottom; + float left; + float right; + +}; + +#endif diff --git a/src/CRESTModel.cpp b/src/CRESTModel.cpp new file mode 100755 index 0000000..bd21bbe --- /dev/null +++ b/src/CRESTModel.cpp @@ -0,0 +1,308 @@ +#include <cstdio> +#include <cstring> +#include <cmath> +#if _OPENMP +#include <omp.h> +#endif +#include "DatedName.h" +#include "AscGrid.h" +#include "CRESTModel.h" + +static const char *stateStrings[] = { + "SM", +}; + +CRESTModel::CRESTModel() { + +} + +CRESTModel::~CRESTModel() { + +} + +bool CRESTModel::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (crestNodes.size() != nodes->size()) { + crestNodes.resize(nodes->size()); + } + + // Fill in modelIndex in the gridNodes + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + node->modelIndex = i; + } + + InitializeParameters(paramSettings, paramGrids); + + return true; +} + +void CRESTModel::InitializeStates(TimeVar *beginTime, char *statePath) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(beginTime->GetTM()); + + char buffer[255]; + for (int p = 0; p < STATE_CREST_QTY; p++) { + sprintf(buffer, "%s/crest_%s_%s.tif", statePath, stateStrings[p], timeStr.GetName()); + + FloatGrid *sGrid = ReadFloatTifGrid(buffer); + if (sGrid) { + printf("Using CREST %s State Grid %s\n", stateStrings[p], buffer); + if (g_DEM->IsSpatialMatch(sGrid)) { + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + CRESTGridNode *cNode = &(crestNodes[i]); + if (sGrid->data[node->y][node->x] != sGrid->noData) { + cNode->states[p] = sGrid->data[node->y][node->x]; + } + } + } else { + GridLoc pt; + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + CRESTGridNode *cNode = &(crestNodes[i]); + if (sGrid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && sGrid->data[pt.y][pt.x] != sGrid->noData) { + cNode->states[p] = sGrid->data[pt.y][pt.x]; + } + } + } + delete sGrid; + } else { + printf("CREST %s State Grid %s not found!\n", stateStrings[p], buffer); + } + } + +} + +void CRESTModel::SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(currentTime->GetTM()); + + std::vector<float> dataVals; + dataVals.resize(nodes->size()); + + char buffer[255]; + for (int p = 0; p < STATE_CREST_QTY; p++) { + sprintf(buffer, "%s/crest_%s_%s.tif", statePath, stateStrings[p], timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + CRESTGridNode *cNode = &(crestNodes[i]); + dataVals[i] = cNode->states[p]; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + } +} + +bool CRESTModel::WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture) { + + size_t numNodes = nodes->size(); + +#if _OPENMP + #pragma omp parallel for +#endif + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + CRESTGridNode *cNode = &(crestNodes[i]); + WaterBalanceInt(node, cNode, stepHours, precip->at(i), pet->at(i), &(fastFlow->at(i)), &(slowFlow->at(i))); + soilMoisture->at(i) = cNode->states[STATE_CREST_SM] * 100.0 / cNode->params[PARAM_CREST_WM]; + } + + return true; +} + +void CRESTModel::WaterBalanceInt(GridNode *node, CRESTGridNode *cNode, float stepHours, float precipIn, float petIn, float *fastFlow, float *slowFlow) { + double precip = precipIn * stepHours; // precipIn is mm/hr, precip is mm + double pet = petIn * stepHours; // petIn in mm/hr, pet is mm + double R = 0.0, Wo = 0.0; + + double adjPET = pet * cNode->params[PARAM_CREST_KE]; + double temX = 0.0; + + // If we aren't a channel cell, add routed in overland to precip + /*if (!node->channelGridCell) { + precip += *fastFlow; + *fastFlow = 0.0; + }*/ + + // We have more water coming in than leaving via ET. + if (precip > adjPET) { + double precipSoil = (precip - adjPET) * (1 - cNode->params[PARAM_CREST_IM]); // This is the precip that makes it to the soil + double precipImperv = precip - adjPET - precipSoil; // Portion of precip on impervious area + + //cNode->states[STATE_CREST_SM] += *slowFlow; + //*slowFlow = 0.0; + + double interflowExcess = cNode->states[STATE_CREST_SM] - cNode->params[PARAM_CREST_WM]; + if (interflowExcess < 0.0) { + interflowExcess = 0.0; + } + + if (cNode->states[STATE_CREST_SM] > cNode->params[PARAM_CREST_WM]) { + cNode->states[STATE_CREST_SM] = cNode->params[PARAM_CREST_WM]; + } + + if (cNode->states[STATE_CREST_SM] < cNode->params[PARAM_CREST_WM]) { + double Wmaxm = cNode->params[PARAM_CREST_WM] * (1 + cNode->params[PARAM_CREST_B]); + double A = Wmaxm * (1 - pow(1 - cNode->states[STATE_CREST_SM] / cNode->params[PARAM_CREST_WM], 1 / (1 + cNode->params[PARAM_CREST_B]))); + if (precipSoil + A >= Wmaxm) { + R = precipSoil - (cNode->params[PARAM_CREST_WM] - cNode->states[STATE_CREST_SM]); // Leftovers after filling SM + + + + if (R < 0) { + printf("R to %f, [%f, %f, %f, %f, %f, %f]\n", R, cNode->params[PARAM_CREST_WM], cNode->params[PARAM_CREST_B], cNode->states[STATE_CREST_SM], A, Wmaxm, precipSoil); + R = 0.0; + } + + Wo = cNode->params[PARAM_CREST_WM]; + + } else { + double infiltration = cNode->params[PARAM_CREST_WM] * (pow(1 - A / Wmaxm, 1 + cNode->params[PARAM_CREST_B]) - pow(1 - (A + precipSoil) / Wmaxm, 1 + cNode->params[PARAM_CREST_B])); + if (infiltration > precipSoil) { + infiltration = precipSoil; + } else if (infiltration < 0.0) { + printf("Infiltration went to %f, [%f, %f, %f, %f, %f, %f]\n", infiltration, cNode->params[PARAM_CREST_WM], cNode->params[PARAM_CREST_B], cNode->states[STATE_CREST_SM], A, Wmaxm, precipSoil); + } + + R = precipSoil - infiltration; + + if (R < 0) { + printf("R (infil) to %f, [%f, %f, %f, %f, %f, %f]\n", R, cNode->params[PARAM_CREST_WM], cNode->params[PARAM_CREST_B], cNode->states[STATE_CREST_SM], A, Wmaxm, precipSoil); + R = 0.0; + } + Wo = cNode->states[STATE_CREST_SM] + infiltration; + } + } else { + R = precipSoil; + Wo = cNode->params[PARAM_CREST_WM]; + } + + // Now R is excess water, split it between overland & interflow + + temX = (cNode->states[STATE_CREST_SM] + Wo) / cNode->params[PARAM_CREST_WM] / 2 * (cNode->params[PARAM_CREST_FC] * stepHours); // Calculate how much water can infiltrate + + if (R <= temX) { + cNode->excess[CREST_LAYER_INTERFLOW] = R; + } else { + cNode->excess[CREST_LAYER_INTERFLOW] = temX; + } + cNode->excess[CREST_LAYER_OVERLAND] = R - cNode->excess[CREST_LAYER_INTERFLOW] + precipImperv; + + cNode->actET = adjPET; + + cNode->excess[CREST_LAYER_INTERFLOW] += interflowExcess; // Extra interflow that got routed. + } else { // All the incoming precip goes straight to ET + cNode->excess[CREST_LAYER_OVERLAND] = 0.0; + + //cNode->states[STATE_CREST_SM] += *slowFlow; + //*slowFlow = 0.0; + + double interflowExcess = cNode->states[STATE_CREST_SM] - cNode->params[PARAM_CREST_WM]; + if (interflowExcess < 0.0) { + interflowExcess = 0.0; + } + cNode->excess[CREST_LAYER_INTERFLOW] = interflowExcess; + + if (cNode->states[STATE_CREST_SM] > cNode->params[PARAM_CREST_WM]) { + cNode->states[STATE_CREST_SM] = cNode->params[PARAM_CREST_WM]; + } + + double ExcessET = (adjPET - precip) * cNode->states[STATE_CREST_SM] / cNode->params[PARAM_CREST_WM]; + if (ExcessET < cNode->states[STATE_CREST_SM]) { + Wo = cNode->states[STATE_CREST_SM] - ExcessET; // We can evaporate away ExcessET too. + } else { + Wo = 0.0; // We don't have enough to evaporate ExcessET. + ExcessET = cNode->states[STATE_CREST_SM]; + } + cNode->actET = ExcessET + precip; + } + + cNode->states[STATE_CREST_SM] = Wo; + + // Add Overland Excess Water to fastFlow + *fastFlow += (cNode->excess[CREST_LAYER_OVERLAND] / (stepHours * 3600.0f)); + + // Add Interflow Excess Water to slowFlow + *slowFlow += (cNode->excess[CREST_LAYER_INTERFLOW] / (stepHours * 3600.0f)); + + // Calculate Discharge as the sum of the leaks + //*discharge = (overlandLeak + interflowLeak) * node->area / 3.6; + +} + +void CRESTModel::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + size_t numNodes = nodes->size(); + size_t unused = 0; + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + CRESTGridNode *cNode = &(crestNodes[i]); + if (!node->gauge) { + unused++; + continue; + } + /*if (i == 0) { + float *paramsBlah = (*paramSettings)[node->gauge]; + printf("Thread %i, %f\n", omp_get_thread_num(), paramsBlah[PARAM_CREST_QTY-1]); + }*/ + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_CREST_QTY); + + // Some of the parameters are special, deal with that here + if (!paramGrids->at(PARAM_CREST_IM)) { + cNode->params[PARAM_CREST_IM] /= 100.0; + } + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_CREST_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && g_DEM->IsSpatialMatch(grid)) { + if (grid->data[node->y][node->x] == 0) { + grid->data[node->y][node->x] = 0.01; + } + cNode->params[paramI] *= grid->data[node->y][node->x]; + } else if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] == 0) { + grid->data[pt.y][pt.x] = 0.01; + //printf("Using nodata value in param %s\n", modelParamStrings[MODEL_CREST][paramI]); + } + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + + if (!paramGrids->at(PARAM_CREST_IWU)) { + cNode->states[STATE_CREST_SM] = cNode->params[PARAM_CREST_IWU] * cNode->params[PARAM_CREST_WM] / 100.0; + } + + if (cNode->states[STATE_CREST_SM] < 0.0) { + printf("Node Soil Moisture(%f) is less than 0, setting to 0.\n", cNode->states[STATE_CREST_SM]); + cNode->states[STATE_CREST_SM] = 0.0; + } else if (cNode->states[STATE_CREST_SM] > cNode->params[PARAM_CREST_WM]) { + printf("Node Soil Moisture(%f) is greater than WM, setting to %f.\n", cNode->states[STATE_CREST_SM], cNode->params[PARAM_CREST_WM]); + } + + if (cNode->params[PARAM_CREST_IM] < 0.0) { + //printf("Node Impervious Area(%f) is less than 0, setting to 0.\n", cNode->params[PARAM_CREST_IM]); + cNode->params[PARAM_CREST_IM] = 0.0; + } else if (cNode->params[PARAM_CREST_IM] > 1.0) { + //printf("Node Impervious Area(%f) is greater than 1, setting to 1.\n", cNode->params[PARAM_CREST_IM]); + cNode->params[PARAM_CREST_IM] = 1.0; + } + + if (cNode->params[PARAM_CREST_B] < 0.0) { + //printf("Node B (%f) is less than 0, setting to 0.\n", cNode->params[PARAM_CREST_B]); + cNode->params[PARAM_CREST_B] = 0.0; + } else if (cNode->params[PARAM_CREST_B] != cNode->params[PARAM_CREST_B]) { + //printf("Node B (%f) NaN, setting to %f.\n", cNode->params[PARAM_CREST_B], 0.0); + cNode->params[PARAM_CREST_B] = 0.0; + } + } + +} diff --git a/src/CRESTModel.h b/src/CRESTModel.h new file mode 100755 index 0000000..03ba8b8 --- /dev/null +++ b/src/CRESTModel.h @@ -0,0 +1,50 @@ +#ifndef CREST_MODEL_H +#define CREST_MODEL_H + +#include "ModelBase.h" + +enum STATES_CREST { + STATE_CREST_SM, + STATE_CREST_QTY +}; + +enum CREST_LAYER { + CREST_LAYER_OVERLAND, + CREST_LAYER_INTERFLOW, + CREST_LAYER_QTY, +}; + +struct CRESTGridNode : BasicGridNode { + float params[PARAM_CREST_QTY]; + float states[STATE_CREST_QTY]; + + //These guys are the state variables + //double soilMoisture; // Current depth of water filling available pore space + + // These are results of the water balance + double excess[CREST_LAYER_QTY]; + double actET; +}; + +class CRESTModel : public WaterBalanceModel { + + public: + CRESTModel(); + ~CRESTModel(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeStates(TimeVar *beginTime, char *statePath); + void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter); + bool WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture); + bool IsLumped() { return false; } + const char *GetName() { return "crest"; } + + private: + void WaterBalanceInt(GridNode *node, CRESTGridNode *cNode, float stepHours, float precipIn, float petIn, float *fastFlow, float *slowFlow); + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + + std::vector<GridNode> *nodes; + std::vector<CRESTGridNode> crestNodes; + +}; + +#endif diff --git a/src/CaliParamConfigSection.cpp b/src/CaliParamConfigSection.cpp new file mode 100755 index 0000000..2c961fc --- /dev/null +++ b/src/CaliParamConfigSection.cpp @@ -0,0 +1,153 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "CaliParamConfigSection.h" + +std::map<std::string, CaliParamConfigSection *> g_caliParamConfigs[MODEL_QTY]; + +CaliParamConfigSection::CaliParamConfigSection(char *nameVal, MODELS modelVal) { + strcpy(name, nameVal); + gauge = NULL; + objSet = false; + model = modelVal; + int numParams = numModelParams[model]; + modelParamMins = new float[numParams]; + modelParamMaxs = new float[numParams]; + modelParamInits = new float[numParams]; + paramsSet = new bool[numParams]; + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamInits, 0, sizeof(float)*numParams); + memset(paramsSet, 0, sizeof(bool)*numParams); + + // ARS Defaults + ars_topNum = 10; + ars_critObjScore = 0.0; + ars_convergenceCriteria = 0.005; + ars_burnInSets = 100; + + // DREAM defaults + dream_ndraw = 10000; + +} + +CaliParamConfigSection::~CaliParamConfigSection() { + delete [] modelParamMins; + delete [] modelParamMaxs; + delete [] modelParamInits; +} + +char *CaliParamConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET CaliParamConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numModelParams[model]; + + if (!strcasecmp(name, "gauge")) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + gauge = itr->second; + } else if (!strcasecmp(name, "objective")) { + for (int i = 0; i < OBJECTIVE_QTY; i++) { + if (!strcasecmp(value, objectiveStrings[i])) { + objSet = true; + objective = (OBJECTIVES)i; + return VALID_RESULT; + } + } + ERROR_LOGF("Unknown objective function option \"%s\"!", value); + INFO_LOGF("Valid objective function options are \"%s\"", "NSCE, CC, SSE"); + return INVALID_RESULT; + } else if (!strcasecmp(name, "ars_topnum")) { + ars_topNum = atoi(value); + return VALID_RESULT; + } else if (!strcasecmp(name, "ars_critobjscore")) { + ars_critObjScore = atof(value); + return VALID_RESULT; + } else if (!strcasecmp(name, "ars_convcriteria")) { + ars_convergenceCriteria = atof(value); + return VALID_RESULT; + } else if (!strcasecmp(name, "ars_burninnum")) { + ars_burnInSets = atoi(value); + return VALID_RESULT; + } else if (!strcasecmp(name, "dream_ndraw")) { + dream_ndraw = atoi(value); + return VALID_RESULT; + } else { + if (!gauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + + //Lets see if this belongs to a parameter + for (int i = 0; i < numParams; i++) { + if (strcasecmp(name, modelParamStrings[model][i]) == 0) { + + if (paramsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + float minVal = 0, maxVal = 0, initVal = 0; + int count = sscanf(value, "%f,%f,%f", &minVal, &maxVal, &initVal); + + if (count < 2) { + ERROR_LOGF("Parameter \"%s\" has invalid calibration values!", name); + return INVALID_RESULT; + } + + modelParamMins[i] = minVal; + modelParamMaxs[i] = maxVal; + modelParamInits[i] = initVal; + paramsSet[i] = true; + + return VALID_RESULT; + } + } + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET CaliParamConfigSection::ValidateSection() { + int numParams = numModelParams[model]; + + if (!gauge) { + ERROR_LOG("The gauge on which calibration is to be performed was not set!"); + return INVALID_RESULT; + } + + if (!objSet) { + ERROR_LOG("The objective function was not specified!"); + return INVALID_RESULT; + } + + for (int i = 0; i < numParams; i++) { + if (!paramsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", modelParamStrings[model][i]); + return INVALID_RESULT; + } + } + + return VALID_RESULT; +} + +bool CaliParamConfigSection::IsDuplicate(char *name, MODELS modelVal) { + std::map<std::string, CaliParamConfigSection *>::iterator itr = g_caliParamConfigs[modelVal].find(name); + if (itr == g_caliParamConfigs[modelVal].end()) { + return false; + } else { + return true; + } +} diff --git a/src/CaliParamConfigSection.h b/src/CaliParamConfigSection.h new file mode 100755 index 0000000..5724650 --- /dev/null +++ b/src/CaliParamConfigSection.h @@ -0,0 +1,58 @@ +#ifndef CONFIG_CALIPARAM_SECTION_H +#define CONFIG_CALIPARAM_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" +#include "ObjectiveFunc.h" + +class CaliParamConfigSection : public ConfigSection { + + public: + CaliParamConfigSection(char *nameVal, MODELS modelVal); + ~CaliParamConfigSection(); + + OBJECTIVES GetObjFunc() { return objective; } + GaugeConfigSection *GetGauge() { return gauge; } + float *GetParamMins() { return modelParamMins; } + float *GetParamMaxs() { return modelParamMaxs; } + float *GetParamInits() { return modelParamInits; } + + // ARS + int ARSGetTopNum() { return ars_topNum; } + float ARSGetCritObjScore() { return ars_critObjScore; } + float ARSGetConvCriteria() { return ars_convergenceCriteria; } + int ARSGetBurnInSets() { return ars_burnInSets; } + + // DREAM + int DREAMGetNDraw() { return dream_ndraw; } + + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name, MODELS modelVal); + + private: + char name[CONFIG_MAX_LEN]; + bool objSet; + MODELS model; + OBJECTIVES objective; + GaugeConfigSection *gauge; + float *modelParamMins; + float *modelParamMaxs; + float *modelParamInits; + bool *paramsSet; + int ars_topNum; + float ars_critObjScore; + float ars_convergenceCriteria; + int ars_burnInSets; + int dream_ndraw; +}; + +extern std::map<std::string, CaliParamConfigSection *> g_caliParamConfigs[]; + +#endif diff --git a/src/Calibrate.h b/src/Calibrate.h new file mode 100755 index 0000000..124eab7 --- /dev/null +++ b/src/Calibrate.h @@ -0,0 +1,21 @@ +#ifndef CALIBRATE_H +#define CALIBRATE_H + +#include "CaliParamConfigSection.h" +#include "ObjectiveFunc.h" +#include "Simulator.h" + +class Calibrate { + public: + virtual void Initialize(CaliParamConfigSection *caliParamConfigNew, RoutingCaliParamConfigSection *routingCaliParamConfigNew, SnowCaliParamConfigSection *snowCaliParamConfigNew, int numParamsWBNew, int numParamsRNew, int numParamsSNew, Simulator *simNew) = 0; + virtual void CalibrateParams() = 0; + + protected: + Simulator *sim; + int numParams, numParamsWB, numParamsR, numParamsS; + CaliParamConfigSection *caliParamConfig; + RoutingCaliParamConfigSection *routingCaliParamConfig; + SnowCaliParamConfigSection *snowCaliParamConfig; +}; + +#endif diff --git a/src/ComputeRP.cpp b/src/ComputeRP.cpp new file mode 100644 index 0000000..31c837a --- /dev/null +++ b/src/ComputeRP.cpp @@ -0,0 +1,136 @@ +#include <stdio.h> +#include <stdlib.h> +#include <cmath> +#include "TifGrid.h" + +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <vector> + +int main(int argc, char** argv) { + struct dirent *dp; + DIR *dfd; + + char *dir ; + dir = argv[1] ; + + if ( argc == 1 ) { + printf("Usage: %s dirname\n",argv[0]); + return 0; + } + + if ((dfd = opendir(dir)) == NULL) { + fprintf(stderr, "Can't open %s\n", dir); + return 0; + } + + std::vector<FloatGrid *> grids; + + char filename_qfd[100] ; + char new_name_qfd[100] ; + + while ((dp = readdir(dfd)) != NULL) { + struct stat stbuf ; + sprintf( filename_qfd , "%s/%s",dir,dp->d_name) ; + if( stat(filename_qfd,&stbuf ) == -1 ) { + printf("Unable to stat file: %s\n",filename_qfd) ; + continue ; + } + + if ( ( stbuf.st_mode & S_IFMT ) == S_IFDIR ) + { + continue; + // Skip directories + } + else + { + + printf("%s\n", filename_qfd); + FloatGrid *precipGrid = ReadFloatTifGrid(filename_qfd); + if (!precipGrid) { + continue; + } + + grids.push_back(precipGrid); + } + } + if (grids.size() > 0) { + FloatGrid *blah = grids[0]; + FloatGrid *avgGrid = new FloatGrid; + avgGrid->numCols = blah->numCols; + avgGrid->numRows = blah->numRows; + avgGrid->cellSize = blah->cellSize; + avgGrid->extent.top = blah->extent.top; + avgGrid->extent.bottom = blah->extent.bottom; + avgGrid->extent.right = blah->extent.right; + avgGrid->extent.left = blah->extent.left; + avgGrid->noData = blah->noData; + avgGrid->data = new float*[avgGrid->numRows]; + FloatGrid *stdGrid = new FloatGrid; + stdGrid->numCols = blah->numCols; + stdGrid->numRows = blah->numRows; + stdGrid->cellSize = blah->cellSize; + stdGrid->extent.top = blah->extent.top; + stdGrid->extent.bottom = blah->extent.bottom; + stdGrid->extent.right = blah->extent.right; + stdGrid->extent.left = blah->extent.left; + stdGrid->noData = blah->noData; + stdGrid->data = new float*[stdGrid->numRows]; + FloatGrid *csGrid = new FloatGrid; + csGrid->numCols = blah->numCols; + csGrid->numRows = blah->numRows; + csGrid->cellSize = blah->cellSize; + csGrid->extent.top = blah->extent.top; + csGrid->extent.bottom = blah->extent.bottom; + csGrid->extent.right = blah->extent.right; + csGrid->extent.left = blah->extent.left; + csGrid->noData = blah->noData; + csGrid->data = new float*[csGrid->numRows]; + for (int i = 0; i < blah->numRows; i++) { + avgGrid->data[i] = new float[blah->numCols]; + stdGrid->data[i] = new float[blah->numCols]; + csGrid->data[i] = new float[blah->numCols]; + } + + float numYears = (float)(grids.size()); + + for (int year = 0; year < grids.size(); year++) { + for (int j = 0; j < avgGrid->numRows; j++) { + for (int i = 0; i < avgGrid->numCols; i++) { + if (year == 0) { + avgGrid->data[j][i] = 0.0; + stdGrid->data[j][i] = 0.0; + csGrid->data[j][i] = 0.0; + } + if (grids[year]->data[j][i] == 0.0) { + grids[year]->data[j][i] = 0.0000001; + } + grids[year]->data[j][i] = log10(grids[year]->data[j][i]); + avgGrid->data[j][i] += (grids[year]->data[j][i] / numYears); + } + } + } + + for (int j = 0; j < avgGrid->numRows; j++) { + for (int i = 0; i < avgGrid->numCols; i++) { + float total = 0.0; + for (int year = 0; year < grids.size(); year++) { + stdGrid->data[j][i] += powf(grids[year]->data[j][i] - avgGrid->data[j][i], 2.0); + total += powf(grids[year]->data[j][i] - avgGrid->data[j][i], 3.0); + } + stdGrid->data[j][i] /= (numYears - 1.0); + stdGrid->data[j][i] = sqrt(stdGrid->data[j][i]); + float csNum = numYears*total; + float csDom = (numYears - 1.0) * (numYears - 2.0) * powf(stdGrid->data[j][i], 3.0); + csGrid->data[j][i] = csNum / csDom; + } + } + + + WriteFloatTifGrid("avgq.tif", avgGrid); + WriteFloatTifGrid("stdq.tif", stdGrid); + WriteFloatTifGrid("csq.tif", csGrid); + } + return 0; +} diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100755 index 0000000..6f65b4b --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,467 @@ + +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "ConfigSection.h" +#include "BasicConfigSection.h" +#include "BasinConfigSection.h" +#include "GaugeConfigSection.h" +#include "PETConfigSection.h" +#include "PrecipConfigSection.h" +#include "TempConfigSection.h" +#include "Model.h" +#include "CaliParamConfigSection.h" +#include "ParamSetConfigSection.h" +#include "TaskConfigSection.h" +#include "EnsTaskConfigSection.h" +#include "ExecuteConfigSection.h" +#include "Config.h" + +Config *g_config = NULL; + +enum CONFIG_PARSE_STATE { + PARSE_NORMAL, + PARSE_CPLUSPLUS_COMMENT, + PARSE_C_COMMENT, + PARSE_BASH_COMMENT, + PARSE_NAME, + PARSE_VALUE, + PARSE_SECTION_NAME, + PARSE_SECTION_VALUE, +}; + +Config::Config(const char *configName) { + //Copy over the config name into the class variable and ensure it is null terminated + strncpy(name, configName, CONFIG_MAX_LEN); + name[CONFIG_MAX_LEN-1] = 0; +} + +Config::~Config() { + +} + +CONFIG_PARSE_RESULTS Config::ParseConfig() { + + FILE *configFile; + size_t fileLen; + char *buffer; + + configFile = fopen(name, "rb"); + if (configFile == NULL) { + ERROR_LOGF("Failed to open configuration file %s\n", name); + return CONFIG_OPENFAILED; + } + + //Get file length + fseek(configFile, 0, SEEK_END); + fileLen = ftell(configFile); + fseek(configFile, 0, SEEK_SET); + + //Read the entire file into buffer, +4 to give us extra room to play with! + buffer = new char[fileLen + 4]; + size_t readLen = fread(buffer, 1, fileLen, configFile); + if (readLen != fileLen) { + ERROR_LOGF("Failed to read configuration file %s\n", name); + delete [] buffer; + return CONFIG_READFAILED; + } + + //Fill the extra space with zeros + buffer[fileLen] = 0; buffer[fileLen + 1] = 0; buffer[fileLen + 2] = 0; buffer[fileLen + 3] = 0; + + //Close the file, we're done with it + fclose(configFile); + + //Start the process of parsing all the information + int line = 1; + char nameBuf[CONFIG_MAX_LEN] = ""; + char valBuf[CONFIG_MAX_LEN] = ""; + size_t i = 0, nameIdx = 0, valIdx = 0; + CONFIG_PARSE_STATE state = PARSE_NORMAL; + ConfigSection *currentSection = NULL; + + //This is the meat of the parsing here + for (i = 0; i < fileLen; i++) { + switch (state) { + case PARSE_NORMAL: { + if (buffer[i] == '/' && buffer[i+1] == '/') { + state = PARSE_CPLUSPLUS_COMMENT; + i++; + continue; + } else if (buffer[i] == '/' && buffer[i+1] == '*') { + state = PARSE_C_COMMENT; + i++; + continue; + } else if (buffer[i] == '#') { + state = PARSE_BASH_COMMENT; + continue; + } else if (buffer[i] == '\r' || buffer[i] == '\t' || buffer[i] == ' ') { + continue; + } else if (buffer[i] == '\n') { + line++; + continue; + } else if (buffer[i] == '[') { + state = PARSE_SECTION_NAME; + nameIdx = 0; + valIdx = 0; + continue; + } else if (currentSection == NULL) { + ERROR_LOGF("%s(%i): Invalid key-value outside of section", name, line); + delete [] buffer; + return CONFIG_INV_NAMEKEY; + } else { + state = PARSE_NAME; + nameBuf[0] = buffer[i]; + nameIdx = 1; + valIdx = 0; + continue; + } + break; + } + case PARSE_CPLUSPLUS_COMMENT: + case PARSE_BASH_COMMENT: { + if (buffer[i] == '\n') { + line++; + state = PARSE_NORMAL; + continue; + } else { + continue; + } + break; + } + case PARSE_C_COMMENT: { + if (buffer[i] == '\n') { + line++; + continue; + } else if (buffer[i] == '*' && buffer[i+1] == '/') { + i++; + state = PARSE_NORMAL; + continue; + } else { + continue; + } + break; + } + case PARSE_SECTION_NAME: { + if (buffer[i] == ' ') { + state = PARSE_SECTION_VALUE; + nameBuf[nameIdx] = 0; //Add the null terminator to the name string + continue; + } else if (buffer[i] == ']') { + state = PARSE_NORMAL; + valBuf[0] = 0; + nameBuf[nameIdx] = 0; + //Allow old section to throw errors + if (currentSection != NULL && currentSection->ValidateSection()) { + ERROR_LOGF("%s(%i): Previous section not valid", name, line); + delete [] buffer; + return CONFIG_INV_SECTION; + } + currentSection = GetConfigSection(nameBuf, valBuf); + if (currentSection == NULL) { + ERROR_LOGF("%s(%i): Unknown section \"%s\"", name, line, nameBuf); + delete [] buffer; + return CONFIG_INV_SECHEAD; + } + continue; + } else if (buffer[i] == '\n') { + //Invalid case! + ERROR_LOGF("%s(%i): Invalid section header contains newline", name, line); + delete [] buffer; + return CONFIG_INV_SECHEAD; + } else { + nameBuf[nameIdx] = buffer[i]; + nameIdx++; + if (nameIdx == CONFIG_MAX_LEN) { + ERROR_LOGF("%s(%i): Section name exceeds max length of %i", name, line, CONFIG_MAX_LEN); + delete [] buffer; + return CONFIG_INV_SECHEAD; + } + continue; + } + break; + } + case PARSE_SECTION_VALUE: { + if (buffer[i] == ']') { + state = PARSE_NORMAL; + valBuf[valIdx] = 0; //Add the null terminator + //Allow old section to throw errors + if (currentSection != NULL && currentSection->ValidateSection()) { + ERROR_LOGF("%s(%i): Previous section not valid", name, line); + delete [] buffer; + return CONFIG_INV_SECTION; + } + currentSection = GetConfigSection(nameBuf, valBuf); + if (currentSection == NULL) { + ERROR_LOGF("%s(%i): Unknown or invalid section \"%s\"", name, line, nameBuf); + delete [] buffer; + return CONFIG_INV_SECHEAD; + } + continue; + } else if (buffer[i] == '\n') { + //Invalid case! + ERROR_LOGF("%s(%i): Invalid section header contains newline", name, line); + delete [] buffer; + return CONFIG_INV_SECHEAD; + } else if (buffer[i] == '\r') { + continue; + } else { + valBuf[valIdx] = buffer[i]; + valIdx++; + if (valIdx == CONFIG_MAX_LEN) { + ERROR_LOGF("%s(%i): Section name exceeds max length of %i", name, line, CONFIG_MAX_LEN); + delete [] buffer; + return CONFIG_INV_SECHEAD; + } + continue; + } + break; + } + case PARSE_NAME: { + if (buffer[i] == '=') { + state = PARSE_VALUE; + nameBuf[nameIdx] = 0; //Add null terminator + continue; + } else if (buffer[i] == '\n') { + nameBuf[nameIdx] = 0; //Add null terminator + ERROR_LOGF("%s(%i): Invalid key (%s) contains newline", name, line, nameBuf); + delete [] buffer; + return CONFIG_INV_NAME; + } else { + nameBuf[nameIdx] = buffer[i]; + nameIdx++; + if (nameIdx == CONFIG_MAX_LEN) { + ERROR_LOGF("%s(%i): Key exceeds max length of %i", name, line, CONFIG_MAX_LEN); + delete [] buffer; + return CONFIG_INV_NAME; + } + continue; + } + break; + } + case PARSE_VALUE: { + if (buffer[i] == ' ' || buffer[i] == '\n' || buffer[i] == '\r') { + state = PARSE_NORMAL; + valBuf[valIdx] = 0; //Add null terminator + if (buffer[i] == '\n') { + line++; + } + //DEBUG_LOGF("Found %s with value %s", nameBuf, valBuf); + if (currentSection->ProcessKeyValue(nameBuf, valBuf)) { + //ProcessKeyValue is responsible for printing error messages + ERROR_LOGF("%s(%i): Invalid key-value pair!", name, line); + delete [] buffer; + return CONFIG_INV_NAMEKEY; + } + continue; + } else { + valBuf[valIdx] = buffer[i]; + valIdx++; + if (valIdx == CONFIG_MAX_LEN) { + ERROR_LOGF("%s(%i): Value exceeds max length of %i", name, line, CONFIG_MAX_LEN); + delete [] buffer; + return CONFIG_INV_NAMEKEY; + } + continue; + } + break; + } + default: + INFO_LOGF("Line(%i): First unprocessed line!", line); + return CONFIG_SUCCESS; + + } + } + + if (state == PARSE_VALUE) { + state = PARSE_NORMAL; + valBuf[valIdx] = 0; //Add null terminator + if (currentSection->ProcessKeyValue(nameBuf, valBuf)) { + //ProcessKeyValue is responsible for printing error messages + ERROR_LOGF("%s(%i): Invalid key-value pair!", name, line); + delete [] buffer; + return CONFIG_INV_NAMEKEY; + } + } + + delete [] buffer; + + if (currentSection != NULL && currentSection->ValidateSection()) { + ERROR_LOGF("%s(%i): Previous section not valid", name, line); + return CONFIG_INV_SECTION; + } + + return CONFIG_SUCCESS; +} + +ConfigSection *Config::GetConfigSection(char *sectionName, char *sectionVal) { + ConfigSection *newSec = NULL; + + if (strcasecmp(sectionName, "basic") == 0) { + g_basicConfig = new BasicConfigSection(); + newSec = g_basicConfig; + } else if (strcasecmp(sectionName, "precipforcing") == 0) { + TOLOWER(sectionVal); + if (PrecipConfigSection::IsDuplicate(sectionVal)) { + ERROR_LOGF("Duplicate Precip section \"%s\"!", sectionVal); + return newSec; + } + PrecipConfigSection *preSec = new PrecipConfigSection(); + g_precipConfigs.insert(std::pair<std::string, PrecipConfigSection *>(sectionVal, preSec)); + newSec = preSec; + } else if (strcasecmp(sectionName, "petforcing") == 0) { + TOLOWER(sectionVal); + if (PETConfigSection::IsDuplicate(sectionVal)) { + ERROR_LOGF("Duplicate PET section \"%s\"!", sectionVal); + return newSec; + } + PETConfigSection *petSec = new PETConfigSection(); + g_petConfigs.insert(std::pair<std::string, PETConfigSection *>(sectionVal, petSec)); + newSec = petSec; + } else if (strcasecmp(sectionName, "tempforcing") == 0) { + TOLOWER(sectionVal); + if (TempConfigSection::IsDuplicate(sectionVal)) { + ERROR_LOGF("Duplicate Temp section \"%s\"!", sectionVal); + return newSec; + } + TempConfigSection *tempSec = new TempConfigSection(); + g_tempConfigs.insert(std::pair<std::string, TempConfigSection *>(sectionVal, tempSec)); + newSec = tempSec; + } else if (strcasecmp(sectionName, "gauge") == 0) { + TOLOWER(sectionVal); + if (GaugeConfigSection::IsDuplicate(sectionVal)) { + ERROR_LOGF("Duplicate Gauge section \"%s\"!", sectionVal); + return newSec; + } + GaugeConfigSection *gaugeSec = new GaugeConfigSection(sectionVal); + g_gaugeConfigs.insert(std::pair<std::string, GaugeConfigSection *>(sectionVal, gaugeSec)); + newSec = gaugeSec; + } else if (strcasecmp(sectionName, "basin") == 0) { + TOLOWER(sectionVal); + if (BasinConfigSection::IsDuplicate(sectionVal)) { + ERROR_LOGF("Duplicate Basin section \"%s\"!", sectionVal); + return newSec; + } + BasinConfigSection *basinSec = new BasinConfigSection(sectionVal); + g_basinConfigs.insert(std::pair<std::string, BasinConfigSection *>(sectionVal, basinSec)); + newSec = basinSec; + } else if (strcasecmp(sectionName, "task") == 0) { + TOLOWER(sectionVal); + if (TaskConfigSection::IsDuplicate(sectionVal)) { + ERROR_LOGF("Duplicate Task section \"%s\"!", sectionVal); + return newSec; + } + TaskConfigSection *taskSec = new TaskConfigSection(sectionVal); + g_taskConfigs.insert(std::pair<std::string, TaskConfigSection *>(sectionVal, taskSec)); + newSec = taskSec; + } else if (strcasecmp(sectionName, "ensembletask") == 0) { + TOLOWER(sectionVal); + if (EnsTaskConfigSection::IsDuplicate(sectionVal)) { + ERROR_LOGF("Duplicate Ensemble Task section \"%s\"!", sectionVal); + return newSec; + } + EnsTaskConfigSection *taskSec = new EnsTaskConfigSection(sectionVal); + g_ensTaskConfigs.insert(std::pair<std::string, EnsTaskConfigSection *>(sectionVal, taskSec)); + newSec = taskSec; + } else if (strcasecmp(sectionName, "execute") == 0) { + g_executeConfig = new ExecuteConfigSection(); + newSec = g_executeConfig; + } else { + TOLOWER(sectionVal); + + //Lets see if this belongs to a water balance model parameter set + for (int i = 0; i < MODEL_QTY; i++) { + if (strcasecmp(sectionName, modelParamSetStrings[i]) == 0) { + if (ParamSetConfigSection::IsDuplicate(sectionVal, (MODELS)i)) { + ERROR_LOGF("Duplicate ParamSet section \"%s\"!", sectionVal); + return newSec; + } + ParamSetConfigSection *psSec = new ParamSetConfigSection(sectionVal, (MODELS)i); + g_paramSetConfigs[i].insert(std::pair<std::string, ParamSetConfigSection *>(sectionVal, psSec)); + newSec = psSec; + break; + } else if (strcasecmp(sectionName, modelCaliParamStrings[i]) == 0) { + if (CaliParamConfigSection::IsDuplicate(sectionVal, (MODELS)i)) { + ERROR_LOGF("Duplicate CaliParam section \"%s\"!", sectionVal); + return newSec; + } + CaliParamConfigSection *cpSec = new CaliParamConfigSection(sectionVal, (MODELS)i); + g_caliParamConfigs[i].insert(std::pair<std::string, CaliParamConfigSection *>(sectionVal, cpSec)); + newSec = cpSec; + break; + } + } + + // Or maybe a routing parameter set + for (int i = 0; i < ROUTE_QTY; i++) { + if (strcasecmp(sectionName, routeParamSetStrings[i]) == 0) { + if (RoutingParamSetConfigSection::IsDuplicate(sectionVal, (ROUTES)i)) { + ERROR_LOGF("Duplicate Routing ParamSet section \"%s\"!", sectionVal); + return newSec; + } + RoutingParamSetConfigSection *psSec = new RoutingParamSetConfigSection(sectionVal, (ROUTES)i); + g_routingParamSetConfigs[i].insert(std::pair<std::string, RoutingParamSetConfigSection *>(sectionVal, psSec)); + newSec = psSec; + break; + } else if (strcasecmp(sectionName, routeCaliParamStrings[i]) == 0) { + if (RoutingCaliParamConfigSection::IsDuplicate(sectionVal, (ROUTES)i)) { + ERROR_LOGF("Duplicate Routing CaliParam section \"%s\"!", sectionVal); + return newSec; + } + RoutingCaliParamConfigSection *cpSec = new RoutingCaliParamConfigSection(sectionVal, (ROUTES)i); + g_routingCaliParamConfigs[i].insert(std::pair<std::string, RoutingCaliParamConfigSection *>(sectionVal, cpSec)); + newSec = cpSec; + break; + } + } + + // Or maybe a snow parameter set + for (int i = 0; i < SNOW_QTY; i++) { + if (strcasecmp(sectionName, snowParamSetStrings[i]) == 0) { + if (SnowParamSetConfigSection::IsDuplicate(sectionVal, (SNOWS)i)) { + ERROR_LOGF("Duplicate Snow ParamSet section \"%s\"!", sectionVal); + return newSec; + } + SnowParamSetConfigSection *psSec = new SnowParamSetConfigSection(sectionVal, (SNOWS)i); + g_snowParamSetConfigs[i].insert(std::pair<std::string, SnowParamSetConfigSection *>(sectionVal, psSec)); + newSec = psSec; + break; + } else if (strcasecmp(sectionName, snowCaliParamStrings[i]) == 0) { + if (SnowCaliParamConfigSection::IsDuplicate(sectionVal, (SNOWS)i)) { + ERROR_LOGF("Duplicate Snow CaliParam section \"%s\"!", sectionVal); + return newSec; + } + SnowCaliParamConfigSection *cpSec = new SnowCaliParamConfigSection(sectionVal, (SNOWS)i); + g_snowCaliParamConfigs[i].insert(std::pair<std::string, SnowCaliParamConfigSection *>(sectionVal, cpSec)); + newSec = cpSec; + break; + } + } + + // Or maybe a inundation parameter set + for (int i = 0; i < INUNDATION_QTY; i++) { + if (strcasecmp(sectionName, inundationParamSetStrings[i]) == 0) { + if (InundationParamSetConfigSection::IsDuplicate(sectionVal, (INUNDATIONS)i)) { + ERROR_LOGF("Duplicate Inundation ParamSet section \"%s\"!", sectionVal); + return newSec; + } + InundationParamSetConfigSection *psSec = new InundationParamSetConfigSection(sectionVal, (INUNDATIONS)i); + g_inundationParamSetConfigs[i].insert(std::pair<std::string, InundationParamSetConfigSection *>(sectionVal, psSec)); + newSec = psSec; + break; + } else if (strcasecmp(sectionName, inundationCaliParamStrings[i]) == 0) { + if (InundationCaliParamConfigSection::IsDuplicate(sectionVal, (INUNDATIONS)i)) { + ERROR_LOGF("Duplicate Inundation CaliParam section \"%s\"!", sectionVal); + return newSec; + } + InundationCaliParamConfigSection *cpSec = new InundationCaliParamConfigSection(sectionVal, (INUNDATIONS)i); + g_inundationCaliParamConfigs[i].insert(std::pair<std::string, InundationCaliParamConfigSection *>(sectionVal, cpSec)); + newSec = cpSec; + break; + } + } + + } + + return newSec; +} diff --git a/src/Config.h b/src/Config.h new file mode 100755 index 0000000..f16ef8c --- /dev/null +++ b/src/Config.h @@ -0,0 +1,32 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include "Defines.h" +#include "ConfigSection.h" + +enum CONFIG_PARSE_RESULTS { + CONFIG_SUCCESS, + CONFIG_OPENFAILED, + CONFIG_READFAILED, + CONFIG_INV_SECTION, + CONFIG_INV_SECHEAD, + CONFIG_INV_NAME, + CONFIG_INV_NAMEKEY, +}; + +class Config { + + public: + Config(const char *configName); + ~Config(); + + CONFIG_PARSE_RESULTS ParseConfig(); + + private: + ConfigSection *GetConfigSection(char *sectionName, char *sectionVal); + + char name[CONFIG_MAX_LEN]; + +}; + +#endif diff --git a/src/ConfigSection.h b/src/ConfigSection.h new file mode 100755 index 0000000..2787daa --- /dev/null +++ b/src/ConfigSection.h @@ -0,0 +1,17 @@ +#ifndef CONFIG_SECTION_H +#define CONFIG_SECTION_H + +enum CONFIG_SEC_RET { + VALID_RESULT, + INVALID_RESULT, +}; + +class ConfigSection { + + public: + virtual CONFIG_SEC_RET ProcessKeyValue(char *name, char *value) = 0; + virtual CONFIG_SEC_RET ValidateSection() = 0; + +}; + +#endif diff --git a/src/DEMProcessor.cpp b/src/DEMProcessor.cpp new file mode 100644 index 0000000..70d4b12 --- /dev/null +++ b/src/DEMProcessor.cpp @@ -0,0 +1,230 @@ +#include <cstdio> +#include <algorithm> +#include <cstring> +#include <cmath> + +#include "Messages.h" +#include "BasicGrids.h" +#include "AscGrid.h" +#include "TifGrid.h" +#include "DEMProcessor.h" + +struct DEMNode { + long x; + long y; + float dem; +}; + +static int ComputeFlowAcc(char *flowAccFile); +static bool SortByHeight(DEMNode *d1, DEMNode *d2); +static bool GetDownstreamNode(long x, long y, long *downX, long *downY); +static bool FlowsInto(DEMNode *d1, DEMNode *d2); + +int ProcessDEM(int mode, char *demFile, char *flowDirFile, char *flowAccFile) { + if (mode == 0) { + ERROR_LOGF("%s", "Invalid mode option specified"); + return 1; + } + + if (mode == 2) { + if (!demFile) { + ERROR_LOG("No DEM file was specified."); + return 2; + } else if (!flowDirFile) { + ERROR_LOG("No Flow Direction file was specified."); + return 2; + } else if (!flowAccFile) { + ERROR_LOG("No Flow Accumulation file was specified."); + return 2; + } + + + INFO_LOGF("Loading DEM: %s", demFile); + char *ext = strrchr(demFile, '.'); + if (!strcasecmp(ext, ".asc")) { + g_DEM = ReadFloatAscGrid(demFile); + } else { + g_DEM = ReadFloatTifGrid(demFile); + } + if (!g_DEM) { + ERROR_LOG("Failed to load DEM!"); + return 2; + } + + INFO_LOGF("Loading DDM: %s", flowDirFile); + ext = strrchr(flowDirFile, '.'); + if (!strcasecmp(ext, ".asc")) { + g_DDM = ReadFloatAscGrid(flowDirFile); + } else { + g_DDM = ReadFloatTifGrid(flowDirFile); + } + if (!g_DDM) { + ERROR_LOG("Failed to load DDM!"); + return 2; + } + if (!g_DEM->IsSpatialMatch(g_DDM)) { + ERROR_LOG("The spatial characteristics of the DEM and DDM differ!"); + return 2; + } + + if (CheckESRIDDM()) { + ReclassifyDDM(); + } + + ComputeFlowAcc(flowAccFile); + + } + + + return 0; +} + +int ComputeFlowAcc(char *flowAccFile) { + std::vector<DEMNode*> nodes; + + g_FAM = new FloatGrid; + g_FAM->extent.left = g_DEM->extent.left; + g_FAM->extent.bottom = g_DEM->extent.bottom; + g_FAM->extent.right = g_DEM->extent.right; + g_FAM->extent.top = g_DEM->extent.top; + g_FAM->numCols = g_DEM->numCols; + g_FAM->numRows = g_DEM->numRows; + g_FAM->cellSize = g_DEM->cellSize; + g_FAM->noData = g_DEM->noData; + + g_FAM->data = new float*[g_FAM->numRows]; + for (long i = 0; i < g_FAM->numRows; i++) { + g_FAM->data[i] = new float[g_FAM->numCols]; + } + + //Grid is setup! Copy over no data values everywhere + for (long row = 0; row < g_FAM->numRows; row++) { + for (long col = 0; col < g_FAM->numCols; col++) { + g_FAM->data[row][col] = g_FAM->noData; + } + } + + for (long row = 0; row < g_DEM->numRows; row++) { + for (long col = 0; col < g_DEM->numCols; col++) { + if (g_DEM->data[row][col] != g_DEM->noData) { + DEMNode *node = new DEMNode; + node->x = col; + node->y = row; + node->dem = g_DEM->data[row][col]; + nodes.push_back(node); + } + } + } + + std::stable_sort(nodes.begin(), nodes.end(), SortByHeight); + + for (std::vector<DEMNode *>::iterator itr = nodes.begin(); itr != nodes.end(); itr++) { + DEMNode *node = *(itr); + if (g_FAM->data[node->y][node->x] == g_FAM->noData) { + g_FAM->data[node->y][node->x] = 0; + } + long downX, downY; + if (GetDownstreamNode(node->x, node->y, &downX, &downY)) { + if (g_FAM->data[downY][downX] == g_FAM->noData) { + g_FAM->data[downY][downX] = 0; + } + g_FAM->data[downY][downX] = g_FAM->data[downY][downX] + g_FAM->data[node->y][node->x] + 1; + //printf("Processing node z %f, current fac %f, down (%f) is %f (%f)\n", node->dem, g_FAM->data[node->y][node->x], g_DDM->data[node->y][node->x], g_FAM->data[downY][downX], g_DEM->data[downY][downX]); + } + } + + WriteFloatTifGrid(flowAccFile, g_FAM); + + return 0; +} + +bool GetDownstreamNode(long x, long y, long *downX, long *downY) { + long nextX = x; + long nextY = y; + + switch ((int)(g_DDM->data[y][x])) { + case FLOW_NORTH: + nextY--; + break; + case FLOW_NORTHEAST: + nextY--; + nextX++; + break; + case FLOW_EAST: + nextX++; + break; + case FLOW_SOUTHEAST: + nextY++; + nextX++; + break; + case FLOW_SOUTH: + nextY++; + break; + case FLOW_SOUTHWEST: + nextY++; + nextX--; + break; + case FLOW_WEST: + nextX--; + break; + case FLOW_NORTHWEST: + nextX--; + nextY--; + break; + default: + return false; + } + + if (nextX >= 0 && nextY >= 0 && nextX < g_DEM->numCols && nextY < g_DEM->numRows && g_DEM->data[nextY][nextX] != g_DEM->noData) { + *downX = nextX; + *downY = nextY; + return true; + } + + return false; +} + +bool SortByHeight(DEMNode *d1, DEMNode *d2) { + if ((d1->x == 115 && d1->y == 55) || (d2->x == 115 && d2->y == 55)) { + printf("Sorting %i %i (%f) to %i %i (%f)\n", (int)d1->x, (int)d1->y, d1->dem, (int)d2->x, (int)d2->y, d2->dem); + } + if (d1->x == d2->x && d1->y == d2->y) { + return false; + } + if (fabsf(d1->dem - d2->dem) < 0.10) { + return FlowsInto(d1, d2); + } else { + return d1->dem > d2->dem; + } +} + +bool FlowsInto(DEMNode *d1, DEMNode *d2) { + long downX, downY; + long curX = d1->x, curY = d1->y; + bool print = false; + if ((d1->x == 115 && d1->y == 55) || (d2->x == 115 && d2->y == 55)) { + print = true; + } + if (print) { + printf("Comparing %i %i (%f) to %i %i (%f)\n", (int)curX, (int)curY, d1->dem, (int)d2->x, (int)d2->y, d2->dem); + } + while (GetDownstreamNode(curX, curY, &downX, &downY)) { + if (d2->x == downX && d2->y == downY) { + if (print) { + printf("true\n"); + } + return true; + } else if (fabsf(d1->dem - g_DEM->data[downY][downX]) > 0.10) { + if (print) { + printf("false\n"); + } + return false; + } + curX = downX; + curY = downY; + } + if (print) { + printf("false2\n"); + } + return false; +} diff --git a/src/DEMProcessor.h b/src/DEMProcessor.h new file mode 100644 index 0000000..e759448 --- /dev/null +++ b/src/DEMProcessor.h @@ -0,0 +1,6 @@ +#ifndef DEMPROCESSOR_H +#define DEMPROCESSOR_H + +int ProcessDEM(int mode, char *demFile, char *flowDirFile, char *flowAccFile); + +#endif diff --git a/src/DREAM.cpp b/src/DREAM.cpp new file mode 100755 index 0000000..6da1362 --- /dev/null +++ b/src/DREAM.cpp @@ -0,0 +1,627 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include <cstdlib> +#include <sys/time.h> +#include <string.h> +#include <cmath> +#if _OPENMP +#include <omp.h> +#endif +#include "DREAM.h" + +void DREAM::Initialize(CaliParamConfigSection *caliParamConfigNew, RoutingCaliParamConfigSection *routingCaliParamConfigNew, SnowCaliParamConfigSection *snowCaliParamConfigNew, int numParamsWBNew, int numParamsRNew, int numParamsSNew, Simulator *simNew) { + caliParamConfig = caliParamConfigNew; + routingCaliParamConfig = routingCaliParamConfigNew; + snowCaliParamConfig = snowCaliParamConfigNew; + numParamsWB = numParamsWBNew; + numParamsR = numParamsRNew; + numParamsS = numParamsSNew; + numParams = numParamsWBNew + numParamsRNew + numParamsSNew; + sim = simNew; + isEnsemble = false; + + // Stuff from CaliParamConfigSection + goal = objectiveGoals[caliParamConfig->GetObjFunc()]; + objectiveString = objectiveStrings[caliParamConfig->GetObjFunc()]; + + /* + // Configurable Parameters + topNum = caliParamConfig->ARSGetTopNum(); + minObjScore = caliParamConfig->ARSGetCritObjScore(); + convergenceCriteria = caliParamConfig->ARSGetConvCriteria(); + burnInSets = caliParamConfig->ARSGetBurnInSets(); + + // Initialize vars & RNG + totalSets = 0; + goodSets = 0;*/ +#ifdef WIN32 + srand(time(NULL)); +#else + srand48(time(NULL)); +#endif + + minParams = new float[numParams]; + maxParams = new float[numParams]; + + INFO_LOGF("num params is %i (water balance :%i, routing: %i, snow: %i)", numParams, numParamsWB, numParamsR, numParamsS); + + // Stuff from CaliParamConfigSection + + memcpy(minParams, caliParamConfig->GetParamMins(), sizeof(float)*numParamsWB); + memcpy(maxParams, caliParamConfig->GetParamMaxs(), sizeof(float)*numParamsWB); + memcpy(&(minParams[numParamsWB]), routingCaliParamConfig->GetParamMins(), sizeof(float)*numParamsR); + memcpy(&(maxParams[numParamsWB]), routingCaliParamConfig->GetParamMaxs(), sizeof(float)*numParamsR); + if (numParamsS > 0) { + memcpy(&(minParams[numParamsWB+numParamsR]), snowCaliParamConfig->GetParamMins(), sizeof(float)*numParamsS); + memcpy(&(maxParams[numParamsWB+numParamsR]), snowCaliParamConfig->GetParamMaxs(), sizeof(float)*numParamsS); + } + + //srand48(0); + pointerMCMC = new DREAM_Parameters(); + pointerInput = new Model_Input(); + + //DREAM Parameters + pointerMCMC->n = numParams; // Dimension of the problem + pointerMCMC->seq = pointerMCMC->n + 0; // Number of Markov Chains / sequences + pointerMCMC->ndraw = caliParamConfig->DREAMGetNDraw(); // Maximum number of function evaluations + pointerMCMC->nCR = 3; // Crossover values used to generate proposals (geometric series) + pointerMCMC->Gamma = 0; // Kurtosis parameter Bayesian Inference Scheme + pointerMCMC->DEpairs = 3; // Number of DEpairs, only 1 or 2? 3 crashes + pointerMCMC->steps = 10; // Number of steps in sem + pointerMCMC->eps = 2e-1; // Random error for ergodicity + strcpy(pointerMCMC->outlierTest, "IQR_Test"); // What kind of test to detect outlier chains? + + float newdraw = floorf((float)pointerMCMC->ndraw / (float)(pointerMCMC->seq*pointerMCMC->steps) + 0.5) * (pointerMCMC->seq*pointerMCMC->steps); + pointerMCMC->ndraw = newdraw; + + pointerInput->MaxT = (int)simNew->GetNumSteps(); + pointerInput->nPar = numParams; //Number of Parameters = Dimension of the problem + pointerInput->ParRangeMin = minParams; + pointerInput->ParRangeMax = maxParams; +} + +void DREAM::Initialize(CaliParamConfigSection *caliParamConfigNew, int numParamsNew, float *paramMins, float *paramMaxs, std::vector<Simulator> *ensSimsNew, std::vector<int> *paramsPerSimNew) { + caliParamConfig = caliParamConfigNew; + numParams = numParamsNew; + ensSims = ensSimsNew; + paramsPerSim = paramsPerSimNew; + isEnsemble = true; + + // Stuff from CaliParamConfigSection + goal = objectiveGoals[caliParamConfig->GetObjFunc()]; +#ifdef WIN32 + srand(time(NULL)); +#else + srand48(time(NULL)); +#endif + pointerMCMC = new DREAM_Parameters(); + pointerInput = new Model_Input(); + //DREAM Parameters + pointerMCMC->n = numParams; + pointerMCMC->seq = pointerMCMC->n + 0; + pointerMCMC->ndraw = caliParamConfig->DREAMGetNDraw(); + pointerMCMC->nCR = 3; + pointerMCMC->Gamma = 0; + pointerMCMC->DEpairs = 3; + pointerMCMC->steps = 10; + pointerMCMC->eps = 2e-1; + strcpy(pointerMCMC->outlierTest, "IQR_Test"); + + float newdraw = floorf((float)pointerMCMC->ndraw / (float)(pointerMCMC->seq*pointerMCMC->steps) + 0.5) * (pointerMCMC->seq*pointerMCMC->steps); + pointerMCMC->ndraw = newdraw; + + pointerInput->MaxT = (int)ensSimsNew->at(0).GetNumSteps(); + pointerInput->nPar = numParams; + pointerInput->ParRangeMin = paramMins; + pointerInput->ParRangeMax = paramMaxs; +} + +void DREAM::CalibrateParams() { + //------VARIABLES BLOCK----------------------------------------------------------// + int i, j, gen_number, ItExtra, start_loc, end_loc; + float *delta_tot, *R2 = NULL, c_std, **r, *std_array, *dnX_array, *delta_normX, *post_array; + float **x, **X, **x_old, **x_new, **newgen, **t_newgen; + float **p, *log_p, *p_old, *log_p_old, **p_xnew, *log_p_xnew, *alpha12, *accept, ***CRpt; + post_Sequences = 1; + struct DREAM_Output *pointerOutput; + bool converged = false; + + //steps = pointerMCMC->steps; //Steps will change, need to kepp original value for memory deallocation + //------Start Messages-----------------------------------------------------------// + INFO_LOGF("%s", "DiffeRential Evolution Adaptive Metropolis (DREAM) Algorithm"); + +#if _OPENMP + if (omp_get_max_threads() > 1) { + INFO_LOGF("Running in parallel mode with %i threads", omp_get_max_threads()); + } else { + INFO_LOGF("%s", "Running in sequential Mode"); + } +#else + INFO_LOGF("%s", "Running in sequential Mode"); +#endif + + + //------Initialize Variables: Call InitVar routine-------------------------------// + InitVar(pointerMCMC, &pointerRUNvar, &pointerOutput); + //------Check for Successful Memory Allocation-----------------------------------// + MEMORYCHECK(pointerRUNvar, "at dream.c: Memory Allocation for DREAM struct run variable not successfull\n"); + MEMORYCHECK(pointerRUNvar->hist_logp, "at dream.c: Memory Allocation for DREAM run variable hist_logp not successfull\n"); + MEMORYCHECK(pointerRUNvar->pCR, "at dream.c: Memory Allocation for DREAM run variable pCR not successfull\n"); + MEMORYCHECK(pointerRUNvar->CR, "at dream.c: Memory Allocation for DREAM run variable CR not successfull\n"); + MEMORYCHECK(pointerRUNvar->lCR, "at dream.c: Memory Allocation for DREAM run variable lCR not successfull\n"); + MEMORYCHECK(pointerOutput,"at dream.c: Memory Allocation for DREAM struct output variable not successfull\n"); + MEMORYCHECK(pointerOutput->AR, "at dream.c: Memory Allocation for DREAM output variable AR not successfull\n"); + MEMORYCHECK(pointerOutput->CR, "at dream.c: Memory Allocation for DREAM output variable CR not successfull\n"); + MEMORYCHECK(pointerOutput->outlier, "at dream.c: Memory Allocation for DREAM output variable outlier not successfull\n"); + MEMORYCHECK(pointerRUNvar->Sequences, "at dream.c: Memory Allocation for DREAM run variable Sequences not successfull\n"); + MEMORYCHECK(pointerRUNvar->Table_JumpRate, "at dream.c: Memory Allocation for DREAM run variable Table_JumpRate not successfull\n"); + //------Step 1: Sample s points in the parameter space---------------------------// + //if Extra.InitPopulation = 'LHS_BASED' + //Latin hypercube sampling when indicated + allocate2D(&x, pointerMCMC->seq, pointerInput->nPar); + LHSU(&x, pointerInput->nPar, pointerInput->ParRangeMax, pointerInput->ParRangeMin, pointerMCMC->seq); + + //Step 2: Calculate posterior density associated with each value in x + allocate2D(&p, pointerMCMC->seq, 2); + MEMORYCHECK(p, "at dream.c: Memory Allocation for DREAM variable p not successfull\n"); + log_p = (float*)malloc(pointerMCMC->seq*sizeof(float)); + MEMORYCHECK(log_p, "at dream.c: Memory Allocation for DREAM variable log_p not successfull\n"); + CompDensity(p, log_p, x, pointerMCMC, pointerInput, 3); + + //Save the initial population, density and log density in one matrix X + allocate2D(&X, pointerMCMC->seq, pointerMCMC->n + 2); + MEMORYCHECK(X, "at dream.c: Memory Allocation for DREAM variable X not successfull\n"); + for (i = 0; i < pointerMCMC->seq; i++) { + for (j = 0; j < pointerMCMC->n; j++) { + X[i][j] = x[i][j]; + } + X[i][pointerInput->nPar] = p[i][0]; + X[i][pointerInput->nPar+1] = log_p[i]; + } + + //Then initialize the sequences + //if save in memory = Yes + InitSequences(X,pointerRUNvar->Sequences,pointerMCMC); + + //Reduced sample collection if reduced_sample_collection = Yes + //iloc_2 = 0; + + //Save N_CR in memory and initialize delta_tot + pointerOutput->CR[0][0] = pointerRUNvar->Iter; + for (i=1;i < pointerMCMC->nCR + 1;i++) { + pointerOutput->CR[0][i] = pointerRUNvar->pCR[0][i-1]; + } + delta_tot = (float *)malloc(pointerMCMC->nCR*sizeof(float)); + MEMORYCHECK(delta_tot, "at dream.c: Memory Allocation for DREAM variable delta_tot not successfull\n"); + for (i=0; i < pointerMCMC->nCR; i++) { + delta_tot[i] = 0.0; + } + + //Save history log density of individual chains + pointerRUNvar->hist_logp[0][0] = pointerRUNvar->Iter; + for (i = 1; i < pointerMCMC->seq + 1; i++) { + pointerRUNvar->hist_logp[0][i] = X[i-1][pointerMCMC->n + 1]; + } + //Compute the R-statistic + pointerOutput->R_stat[0][0] = pointerRUNvar->Iter; + Gelman(pointerOutput->R_stat, 0, pointerRUNvar->Sequences, pointerRUNvar->iloc, pointerMCMC->n, pointerMCMC->seq, 0); + + //Allocate Variables + allocate2D(&x_old, pointerMCMC->seq, pointerMCMC->n); + MEMORYCHECK(x_old, "at dream.c: Memory Allocation for DREAM variable x_old not successfull\n"); + p_old = (float*)malloc(pointerMCMC->seq*sizeof(float*)); + MEMORYCHECK(p_old, "at dream.c: Memory Allocation for DREAM variable p_old not successfull\n"); + log_p_old = (float*)malloc(pointerMCMC->seq*sizeof(float*)); + MEMORYCHECK(log_p_old, "at dream.c: Memory Allocation for DREAM variable log_p_old not successfull\n"); + allocate2D(&x_new, pointerMCMC->seq, pointerMCMC->n); + MEMORYCHECK(x_new, "at dream.c: Memory Allocation for DREAM variable x_new not successfull\n"); + allocate2D(&p_xnew, pointerMCMC->seq, 2); + MEMORYCHECK(p_xnew, "at dream.c: Memory Allocation for DREAM variable p_xnew not successfull\n"); + log_p_xnew = (float*)malloc(pointerMCMC->seq*sizeof(float)); + MEMORYCHECK(log_p_xnew, "at dream.c: Memory Allocation for DREAM variable log_p_xnew not successfull\n"); + alpha12 = (float*)malloc(pointerMCMC->seq*sizeof(float*)); + MEMORYCHECK(alpha12, "at dream.c: Memory Allocation for DREAM variable alpha12 not successfull\n"); + accept = (float*)malloc(pointerMCMC->seq*sizeof(float*)); + MEMORYCHECK(accept, "at dream.c: Memory Allocation for DREAM variable accept not successfull\n"); + + // Preallocate memory needed here + allocate2D(&newgen, pointerMCMC->seq, pointerMCMC->n + 2); + MEMORYCHECK(newgen, "at dream.c: Memory Allocation for DREAM variable newgen not successfull\n"); + allocate2D(&r, pointerMCMC->seq, pointerMCMC->n + 2); + MEMORYCHECK(r, "at dream.c: Memory Allocation for DREAM variable r not successfull\n"); + std_array = (float*)malloc(pointerMCMC->seq*sizeof(float)); + MEMORYCHECK(std_array, "at dream.c: Memory Allocation for DREAM variable std_array not successfull\n"); + delta_normX = (float*)malloc(pointerMCMC->seq*sizeof(float)); + MEMORYCHECK(delta_normX, "at dream.c: Memory Allocation for DREAM variable delta_normX not successfull\n"); + dnX_array = (float*)malloc((pointerMCMC->n+2)*sizeof(float)); + MEMORYCHECK(dnX_array, "at dream.c: Memory Allocation for DREAM variable dnX_array not successfull\n"); + allocate2D(&t_newgen, pointerMCMC->n + 2, pointerMCMC->seq); + +#ifdef _WIN32 + setIteration(0); +#endif + + //Now start iteration ... + while ((pointerRUNvar->Iter < pointerMCMC->ndraw) && !converged) { + //Loop a number of times + for (gen_number = 0; gen_number < pointerMCMC->steps; gen_number++) { + //Initialize DR properties + //accept2 = 0; + ItExtra = 0; + pointerRUNvar->new_teller = pointerRUNvar->new_teller + 1; + + //Define the current locations and associated posterior densities + GetLocation(x_old, p_old, log_p_old, X, pointerMCMC); + + //Now generate candidate in each sequence using current point and members of X + offde(x_new, x_old, X, pointerRUNvar->CR, pointerMCMC, pointerRUNvar->Table_JumpRate, pointerInput, "Reflect", R2, "No"); + + //Now compute the likelihood of the new points + CompDensity(p_xnew, log_p_xnew, x_new, pointerMCMC, pointerInput, 3); + + //Now apply the acceptance/rejectance rule for the chain itself + metrop(newgen, alpha12, accept, x_new, p_xnew, log_p_xnew, x_old, p_old, log_p_old, pointerInput, pointerMCMC, 3); + + //Check whether we do delayed rejection or not + //If DR = "Yes", then do compute several things. For this implementation of DREAM, + //We skipped said computations (i.e. DR = "No") + + //Define the location in the sequence + //if strcmp(Extra.save_in_memory,'Yes'); + pointerRUNvar->iloc = pointerRUNvar->iloc + 1; + + //Now update the locations of the Sequences with the current locations + transp(newgen, pointerMCMC->seq, pointerMCMC->n + 2, &t_newgen, true); + for (i=0;i < pointerMCMC->n + 2;i++) { + for (j=0;j < pointerMCMC->seq;j++) { + pointerRUNvar->Sequences[pointerRUNvar->iloc-1][i][j] = t_newgen[i][j]; + } + } + + //And update X using current members of Sequences + for (i=0;i < pointerMCMC->n + 2;i++) { + for (j=0;j < pointerMCMC->seq;j++) { + X[j][i] = newgen[j][i]; + } + } + + //if strcmp(Extra.pCR,'Update'); + //Calculate the standard deviation of each dimension of X + + for (j = 0; j < pointerMCMC->n + 2; j++) { + for (i = 0; i < pointerMCMC->seq; i++) { + std_array[i] = X[i][j]; + } + c_std = meanvar(std_array, pointerMCMC->seq, MVOP_STD); + for (i=0;i < pointerMCMC->seq;i++) { + r[i][j] = c_std; + } + } + + for (i = 0; i < pointerMCMC->seq; i++) { + for (j = 0; j < pointerMCMC->n + 2; j++) { + dnX_array[j] = powf((x_old[i][j] - X[i][j])/r[i][j], 2); + } + delta_normX[i] = sumarray(dnX_array,pointerMCMC->n + 2, 1); + } + + //Use this information to update sum_p2 to update N_CR + CalcDelta(delta_tot, pointerMCMC, delta_normX, pointerRUNvar, gen_number); + + //Update hist_logp + pointerRUNvar->hist_logp[pointerRUNvar->counter-1][0] = pointerRUNvar->Iter; + + for (j = 1; j < pointerMCMC->seq+1; j++) { + pointerRUNvar->hist_logp[pointerRUNvar->counter-1][j] = X[j-1][pointerMCMC->n+1]; + } + + //Save some important output -- Acceptance Rate + pointerOutput->AR[pointerRUNvar->counter-1][0] = pointerRUNvar->Iter; + //Next Line, variable accept2 not included in this implementation of DREAM since Extra.DR = 'No' + pointerOutput->AR[pointerRUNvar->counter-1][1] = 100.0 * (sumarray(accept,pointerMCMC->seq,1) / (float)((pointerMCMC->seq + ItExtra))); + + //Update Iteration and counter + pointerRUNvar->Iter = pointerRUNvar->Iter + pointerMCMC->seq + ItExtra; +#ifdef _WIN32 + setIteration(pointerRUNvar->Iter); +#else + if ((pointerRUNvar->Iter % 400) == 0) { + INFO_LOGF("Completed %i simulations so far!", pointerRUNvar->Iter); + } +#endif + pointerRUNvar->counter = pointerRUNvar->counter + 1; + } //for (gen_number=0;gen_number < 1;gen_number++) + //-----------End of: for (gen_number=0;gen_number < 1;gen_number++)----------------------- // + + //Store Important Diagnostic information -- Probability of individual crossover values + pointerOutput->CR[pointerRUNvar->teller-1][0] = pointerRUNvar->Iter; + for (i = 1; i < pointerMCMC->nCR + 1; i++) { + pointerOutput->CR[pointerRUNvar->teller-1][i] = pointerRUNvar->pCR[0][i-1]; + } + + //Do this to get rounded iteration numbers + if (pointerRUNvar->teller == 2) { + pointerMCMC->steps = pointerMCMC->steps + 1; + } + + //Check whether to update individual pCR values + if (pointerRUNvar->Iter <= (0.1*pointerMCMC->ndraw)) { + //if strcmp(Extra.pCR,'Update'); + //Update pCR values + AdaptpCR(pointerRUNvar, pointerMCMC, delta_tot); + } else { + //See whether there are any outlier chains, and remove them to current best value of X + RemOutLierChains(X, pointerRUNvar, pointerMCMC, pointerOutput); + } + + //if strcmp(Extra.pCR,'Update'); + //Generate CR values based on current pCR values + CRpt = &(pointerRUNvar)->CR; + GenCR(&pointerMCMC, &(pointerRUNvar)->pCR, &CRpt); + + //Calculate Gelman and Rubin convergence diagnostic + //if strcmp(Extra.save_in_memory,'Yes'); + if (floorf(0.5 * pointerRUNvar->iloc) > 1) { + start_loc = floorf(0.5 * pointerRUNvar->iloc); + } else { + start_loc = 1; + } + end_loc = pointerRUNvar->iloc; + + //Compute the R-statistic using 50% burn-in from Sequences + Gelman(pointerOutput->R_stat, pointerRUNvar->teller-1, pointerRUNvar->Sequences, (end_loc-start_loc+1), pointerMCMC->n, pointerMCMC->seq, start_loc); + pointerOutput->R_stat[pointerRUNvar->teller-1][0] = pointerRUNvar->Iter; + + // Lets see if we converged or not + converged = true; + NORMAL_LOGF("R_stat: %f ", pointerOutput->R_stat[pointerRUNvar->teller-1][0]); + for (j = 0; j < pointerMCMC->n; j++) { + NORMAL_LOGF("%f ", pointerOutput->R_stat[pointerRUNvar->teller-1][j + 1]); + if (pointerOutput->R_stat[pointerRUNvar->teller-1][j + 1] > 1.2 || pointerOutput->R_stat[pointerRUNvar->teller-1][j + 1] == -2.0) { + converged = false; + } + } + NORMAL_LOGF("%s", "\n"); + if (converged) { + INFO_LOGF("%s","DREAM has converged on a solution!"); + } + //Update the Teller + pointerRUNvar->teller = pointerRUNvar->teller + 1; + } //while (pointerRUNvar->Iter < pointerMCMC->ndraw) + + // Deallocate preallocated memory here + deallocate2D(&t_newgen, pointerMCMC->seq); + deallocate2D(&newgen, pointerMCMC->seq); + deallocate2D(&r, pointerMCMC->seq); + free(std_array); + free(delta_normX); + free(dnX_array); + + //Postprocess output from DREAM before returning arguments + post_array = (float*)malloc((pointerMCMC->n+2)*sizeof(float)); + MEMORYCHECK(post_array, "at dream.c: Memory Allocation for DREAM variable post_array not successfull\n"); + for (i = 0; i < floorf(1.25 * pointerRUNvar->Nelem); i++) { + for (j = 0; j < pointerMCMC->n+2; j++) { + post_array[j] = pointerRUNvar->Sequences[i][j][0]; + } + if (sumarray(post_array, pointerMCMC->n+2, 1) == 0) { + post_Sequences = i-1; + break; + } + } + free(post_array); + + /* + for (i = 0; i < pointerRUNvar->teller - 1; i++) { + printf("T: %i ", i); + for (j = 0; j < pointerMCMC->n + 1; j++) { + printf("%f ", pointerOutput->R_stat[i][j]); + } + printf("\n"); + }*/ + + /* + //Generate a 2D matrix with samples + allocate2D(&ParSet, post_Sequences*pointerMCMC->seq, pointerMCMC->n+2); + GenParSet(ParSet, pointerRUNvar, post_Sequences, pointerMCMC); + + //------Deallocating Memory------------------------------------------------------// + for (i = 0; i < floorf(1.25 * pointerRUNvar->Nelem); i++) { + for (j=0; j < pointerMCMC->n+2; j++) { + free(pointerRUNvar->Sequences[i][j]); + } + free(pointerRUNvar->Sequences[i]); + } + free(pointerRUNvar->Sequences); + + deallocate2D(&ParSet, post_Sequences*pointerMCMC->seq); + */ + + /*deallocate2D(&pointerRUNvar->hist_logp, pointerRUNvar->Nelem - 1 + 10); + deallocate2D(&pointerRUNvar->pCR, 1); + deallocate2D(&pointerRUNvar->CR, pointerMCMC->seq); + deallocate2D(&pointerRUNvar->Table_JumpRate, pointerMCMC->n); + deallocate2D(&pointerOutput->AR, pointerRUNvar->Nelem+10); + deallocate2D(&pointerOutput->CR, floorf(pointerRUNvar->Nelem / steps) + 10); + deallocate2D(&pointerOutput->outlier, pointerMCMC->ndraw); + deallocate2D(&pointerOutput->R_stat, floorf((pointerRUNvar->Nelem+10) / steps)); + free(pointerRUNvar->lCR); + free(pointerOutput); + //free(pointerRUNvar); + deallocate2D(&x, pointerMCMC->seq); + deallocate2D(&X, pointerMCMC->seq); + deallocate2D(&p, pointerMCMC->seq); + deallocate2D(&p_xnew, pointerMCMC->seq); + deallocate2D(&x_old, pointerMCMC->seq); + deallocate2D(&x_new, pointerMCMC->seq); + free(log_p); + free(log_p_xnew); + free(alpha12); + free(accept); + free(delta_tot); + free(p_old); + free(log_p_old);*/ + INFO_LOGF("%s","End of DREAM Routine"); + +} + +void DREAM::WriteOutput(char *outputFile, MODELS model, ROUTES route, SNOWS snow) { + FILE *file = fopen(outputFile, "w"); + int i; + float **ParSet; + float *bestParams = new float[pointerMCMC->n]; + + for (i = 0; i < numModelParams[model]; i++) { + fprintf(file, "%s%s", (i == 0) ? "" : ",", modelParamStrings[model][i]); + } + int endi = numModelParams[model] + numRouteParams[route]; + for (i = numModelParams[model]; i < endi; i++) { + fprintf(file, ",%s", routeParamStrings[route][i-numModelParams[model]]); + } + + if (snow != SNOW_QTY) { + int starti = numModelParams[model] + numRouteParams[route]; + int endi = numModelParams[model] + numRouteParams[route] + numSnowParams[snow]; + for (i = starti; i < endi; i++) { + fprintf(file, ",%s\n", snowParamStrings[snow][i-starti]); + } + } + + fprintf(file, ",%s,%s/2%s", objectiveString, objectiveString, "\n"); + + //Generate a 2D matrix with samples + allocate2D(&ParSet, post_Sequences*pointerMCMC->seq, pointerMCMC->n+2); + GenParSet(ParSet, pointerRUNvar, post_Sequences, pointerMCMC, file, bestParams); + + //------Deallocating Memory------------------------------------------------------// + /*for (i = 0; i < floorf(1.25 * pointerRUNvar->Nelem); i++) { + for (j=0; j < pointerMCMC->n+2; j++) { + free(pointerRUNvar->Sequences[i][j]); + } + free(pointerRUNvar->Sequences[i]); + } + free(pointerRUNvar->Sequences);*/ + deallocate2D(&ParSet, post_Sequences*pointerMCMC->seq); + //free(pointerRUNvar); + fprintf(file, "[WaterBalance]\n"); + for (i = 0; i < numModelParams[model]; i++) { + fprintf(file, "%s=%f\n", modelParamStrings[model][i], bestParams[i]); + } + fprintf(file, "[Routing]\n"); + endi = numModelParams[model] + numRouteParams[route]; + for (i = numModelParams[model]; i < endi; i++) { + fprintf(file, "%s=%f\n", routeParamStrings[route][i-numModelParams[model]], bestParams[i]); + } + + if (snow != SNOW_QTY) { + fprintf(file, "[Snow]\n"); + int starti = numModelParams[model] + numRouteParams[route]; + int endi = numModelParams[model] + numRouteParams[route] + numSnowParams[snow]; + for (i = starti; i < endi; i++) { + fprintf(file, "%s=%f\n", snowParamStrings[snow][i-starti], bestParams[i]); + } + } + + fclose(file); +} + +void DREAM::CompDensity(float **p, float *log_p, float **x, struct DREAM_Parameters *MCMC, struct Model_Input *Input, int option) { + //This function computes the density of each x value + float objScore; + int count = MCMC->seq; + int i = 0; + + //#pragma omp parallel for private(objScore, i) + if (!isEnsemble) { +#if _OPENMP +#pragma omp parallel for +#endif + for (i = 0; i < count; i++) { + float score = sim->SimulateForCali(&(x[i][0])); + objScore = ((goal == OBJECTIVE_GOAL_MINIMIZE) ? -1.0 : 1.0f) * score; +#if _OPENMP + printf("%i (%i) %f\n", i, omp_get_thread_num(), score); +#endif + p[i][0] = objScore; + p[i][1] = i; + log_p[i] = 0.5 * objScore; + } + } else { + // Ensemble calculate RHRE + int numEns = (int)ensSims->size(); + int numObs = (int)ensSims->at(0).GetNumSteps(); + float *obsVals = ensSims->at(0).GetObsTS(); + float *dischargeVals[numEns]; + float currentDischargeSet[numEns]; + int bin_tally[numEns + 1]; + + for (i = 0; i < count; i++) { + int paramIndex = 0; + + for (int z = 0; z < numEns + 1; z++) { + bin_tally[z] = 0; + } + + for (int j = 0; j < numEns; j++) { + dischargeVals[j] = ensSims->at(j).SimulateForCaliTS(&(x[i][paramIndex])); + paramIndex += paramsPerSim->at(j); + } + + for (int j = 0; j < numObs; j++) { + for (int k = 0; k < numEns; k++) { + currentDischargeSet[k] = -9999.0; + } + + for (int k = 0; k < numEns; k++) { + float cVal = dischargeVals[k][j]; + //printf("d%i: %f\n", k, cVal); + for (int z = numEns - 1; z >= 0; z--) { + //printf("test %f, %f, %i\n", cVal, currentDischargeSet[z], z); + if (cVal >= currentDischargeSet[z]) { + float tempVal = currentDischargeSet[z]; + currentDischargeSet[z] = cVal; + //printf("dSet%i: %f\n", k, cVal); + cVal = tempVal; + if (cVal == -9999) { + break; + } + } + } + //currentDischargeSet[k] = dischargeVals[k][j]; + } + + //printf("d: %f %f %f\n", currentDischargeSet[0], currentDischargeSet[1], currentDischargeSet[2]); + + float obsVal = obsVals[j]; + int bin; + for (bin = numEns - 1; bin >= 0; bin--) { + if (obsVal >= currentDischargeSet[bin]) { + break; + } + } + bin_tally[bin + 1]++; + } + + float distMax = bin_tally[0], distExpected = 1.0 / ((float)(numEns) + 1.0); + for (int z = 0; z < numEns + 1; z++) { + if (distMax < bin_tally[z]) { + distMax = bin_tally[z]; + } + } + //printf("t: %i %i %i %i\n", bin_tally[0], bin_tally[1], bin_tally[2], bin_tally[3]); + distMax /= ((float)(numObs)); + objScore = fabs((distMax - distExpected)/distExpected) * 100.0; + //printf("%f %f %f %f\n", distExpected, distMax, objScore, (float)(numObs)); + p[i][0] = -1 * objScore; + p[i][1] = i; + log_p[i] = -0.5 * objScore; + + for (int j = 0; j < numEns; j++) { + delete [] dischargeVals[j]; + } + } + + delete [] obsVals; + } +} diff --git a/src/DREAM.h b/src/DREAM.h new file mode 100755 index 0000000..a869914 --- /dev/null +++ b/src/DREAM.h @@ -0,0 +1,35 @@ +#ifndef DREAM_H +#define DREAM_H + +#include "Calibrate.h" +#include "Model.h" +#include "dream_variables.h" +#include "misc_functions.h" +#include "dream_functions.h" + + +class DREAM : public Calibrate { + public: + void Initialize(CaliParamConfigSection *caliParamConfigNew, RoutingCaliParamConfigSection *routingCaliParamConfigNew, SnowCaliParamConfigSection *snowCaliParamConfigNew, int numParamsWBNew, int numParamsRNew, int numParamsSNew, Simulator *simNew); + void Initialize(CaliParamConfigSection *caliParamConfigNew, int numParamsNew, float *paramMins, float *paramMaxs, std::vector<Simulator> *ensSimsNew, std::vector<int> *paramsPerSimNew); + void CalibrateParams(); + void WriteOutput(char *outputFile, MODELS model, ROUTES route, SNOWS snow); + + private: + void CompDensity(float **p, float *log_p, float **x, struct DREAM_Parameters *MCMC, struct Model_Input *Input, int option); + + float *minParams; + float *maxParams; + struct DREAM_Parameters *pointerMCMC; + struct Model_Input *pointerInput; + OBJECTIVE_GOAL goal; + const char *objectiveString; + bool isEnsemble; + std::vector<Simulator> *ensSims; + std::vector<int> *paramsPerSim; + + int post_Sequences; + struct DREAM_Variables *pointerRUNvar; +}; + +#endif diff --git a/src/DamConfigSection.cpp b/src/DamConfigSection.cpp new file mode 100755 index 0000000..7566227 --- /dev/null +++ b/src/DamConfigSection.cpp @@ -0,0 +1,131 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <limits> +#include "Messages.h" +#include "DamConfigSection.h" + +std::map<std::string, DamConfigSection *> g_damConfigs; + +DamConfigSection::DamConfigSection(char *nameVal) { + obsSet = false; + latSet = false; + lonSet = false; + xSet = false; + ySet = false; + obsFlowAccumSet = false; + volumeSet = false; + strcpy(name, nameVal); + outputTS = true; + observation[0] = 0; + wantDA = true; + wantCO = false; +} + +DamConfigSection::~DamConfigSection() { + +} + +char *DamConfigSection::GetName() { + return name; +} + +void DamConfigSection::LoadTS() { + if (observation[0]) { + obs.LoadTimeSeries(observation); + } +} + +float DamConfigSection::GetObserved(TimeVar *currentTime) { + if (!obs.GetNumberOfObs()) { + return std::numeric_limits<float>::quiet_NaN(); + } + return obs.GetValueAtTime(currentTime); +} + +float DamConfigSection::GetObserved(TimeVar *currentTime, float diff) { + if (!obs.GetNumberOfObs()) { + return std::numeric_limits<float>::quiet_NaN(); + } + return obs.GetValueNearTime(currentTime, diff); +} + +void DamConfigSection::SetObservedValue(char *timeBuffer, float dataValue) { + obs.PutValueAtTime(timeBuffer, dataValue); +} + +CONFIG_SEC_RET DamConfigSection::ProcessKeyValue(char *name, char *value) { + + if (!strcasecmp(name, "lat")) { + lat = strtod(value, NULL); + latSet = true; + } else if (!strcasecmp(name, "lon")) { + lon = strtod(value, NULL); + lonSet = true; + } else if (!strcasecmp(name, "cellx")) { + SetCellX(atoi(value)); + xSet = true; + } else if (!strcasecmp(name, "celly")) { + SetCellY(atoi(value)); + ySet = true; + } else if (!strcasecmp(name, "basinarea")) { + obsFlowAccum = atof(value); + obsFlowAccumSet = true; + } else if (!strcasecmp(name, "volume")) { + volume = atof(value); + volumeSet = true; + } else if (!strcasecmp(name, "obs")) { + strcpy(observation, value); + obsSet = true; + } else if (!strcasecmp(name, "outputts")) { + if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) { + outputTS = false; + } else if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) { + outputTS = true; + } else { + // Unknown value + } + outputTSSet = true; + } else if (!strcasecmp(name, "wantda")) { + if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) { + wantDA = false; + } else if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) { + wantDA = true; + } else { + // Unknown value + } + } else if (!strcasecmp(name, "wantco")) { + if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) { + wantCO = false; + } else if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) { + wantCO = true; + } else { + // Unknown value + } + } + return VALID_RESULT; +} + +CONFIG_SEC_RET DamConfigSection::ValidateSection() { + if (!latSet && !ySet) { + ERROR_LOG("The latitude was not specified"); + return INVALID_RESULT; + } else if (!lonSet && !xSet) { + ERROR_LOG("The longitude was not specified"); + return INVALID_RESULT; + } else if (!volumeSet) { + ERROR_LOG("Missing dam volume"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +bool DamConfigSection::IsDuplicate(char *name) { + std::map<std::string, DamConfigSection *>::iterator itr = g_damConfigs.find(name); + if (itr == g_damConfigs.end()) { + return false; + } else { + return true; + } +} diff --git a/src/DamConfigSection.h b/src/DamConfigSection.h new file mode 100755 index 0000000..bb8c37f --- /dev/null +++ b/src/DamConfigSection.h @@ -0,0 +1,69 @@ +#ifndef CONFIG_DAM_SECTION_H +#define CONFIG_DAM_SECTION_H + +#include <map> +#include <string> +#include "Defines.h" +#include "Grid.h" +#include "ConfigSection.h" +#include "TimeSeries.h" +#include "TimeVar.h" + +class DamConfigSection : public ConfigSection { + + public: + DamConfigSection(char *nameVal); + ~DamConfigSection(); + + char *GetName(); + float GetLat() { return lat; } + float GetLon() { return lon; } + long GetGridNodeIndex() { return gridNodeIndex; } + bool GetUsed() { return used; } + bool OutputTS() { return outputTS; } + bool WantDA() { return wantDA; } + bool WantCO() { return wantCO; } + long GetFlowAccum() { return flowAccum; } + bool HasObsFlowAccum() { return obsFlowAccumSet; } + float GetObsFlowAccum() { return obsFlowAccum; } + float GetVolume() { return volume; } + GridLoc *GetGridLoc() { return &gridLoc; } + float GetObserved(TimeVar *currentTime); + float GetObserved(TimeVar *currentTime, float diff); + void SetObservedValue(char *timeBuffer, float dataValue); + void LoadTS(); + void SetGridNodeIndex(long newVal) { gridNodeIndex = newVal; } + void SetLat(float newVal) { lat = newVal; } + void SetLon(float newVal) { lon = newVal; } + void SetCellX(long newX) { gridLoc.x = newX; } + void SetCellY(long newY) { gridLoc.y = newY; } + void SetUsed(bool newVal) { used = newVal; } + void SetFlowAccum(long newVal) { flowAccum = newVal; } + bool NeedsProjecting() { return latSet; } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name); + + private: + bool obsSet, latSet, lonSet, xSet, ySet, obsFlowAccumSet, outputTSSet, volumeSet; + bool outputTS, wantDA, wantCO; + char observation[CONFIG_MAX_LEN]; + char name[CONFIG_MAX_LEN]; + float lat; + float lon; + float obsFlowAccum; + float volume; + TimeSeries obs; + + //These are for basin carving procedures! + long flowAccum; + bool used; + GridLoc gridLoc; + long gridNodeIndex; + +}; + +extern std::map<std::string, DamConfigSection *> g_damConfigs; + +#endif diff --git a/src/DatedName.cpp b/src/DatedName.cpp new file mode 100755 index 0000000..d9d8bba --- /dev/null +++ b/src/DatedName.cpp @@ -0,0 +1,81 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "DatedName.h" + +const char *datedNameStrings[] = { + "YYYY", + "MM", + "DD", + "HH", + "UU", + "SS", +}; + +const int datePartLen[] = { + 4, + 2, + 2, + 2, + 2, + 2, +}; + +void DatedName::SetNameStr(const char *nameStr) { + strcpy(inUseName, nameStr); + memset(inUseTimeParts, 0, sizeof(bool)*TIME_UNIT_QTY); +} + +bool DatedName::ProcessName(TimeUnit *freq) { + resolution = freq->GetTimeUnit(); + + // Verify that our name string has all of the necessary variables + // for the resolution specified by frequency + for (int i = 0; i <= resolution; i++) { + timeParts[i] = strstr(inUseName, datedNameStrings[i]); + if (timeParts[i] == NULL) { + ERROR_LOGF("Expected to find \"%s\" in \"%s\" but it was not found!", datedNameStrings[i], inUseName); + return false; + } + inUseTimeParts[i] = true; + } + + return true; +} + +bool DatedName::ProcessNameLoose(TimeUnit *freq) { + //resolution = freq->GetTimeUnit(); + resolution = SECONDS; + + // Verify that our name string has all of the necessary variables + // for the resolution specified by frequency + for (int i = 0; i <= resolution; i++) { + timeParts[i] = strstr(inUseName, datedNameStrings[i]); + if (timeParts[i] != NULL) { + inUseTimeParts[i] = true; + } + } + + return true; +} + + +void DatedName::UpdateName(tm *ptm) { + char dateParts[6][5]; + + memset(dateParts, 0, 6*5); //Zero out the buffer memory + sprintf(dateParts[0], "%04d", ptm->tm_year + 1900); + sprintf(dateParts[1], "%02d", ptm->tm_mon + 1); + sprintf(dateParts[2], "%02d", ptm->tm_mday); + sprintf(dateParts[3], "%02d", ptm->tm_hour); + sprintf(dateParts[4], "%02d", ptm->tm_min); + sprintf(dateParts[5], "%02d", ptm->tm_sec); + + for (int i = 0; i <= resolution; i++) { + if (inUseTimeParts[i]) { + memcpy(timeParts[i], dateParts[i], datePartLen[i]); + } + } + +} + diff --git a/src/DatedName.h b/src/DatedName.h new file mode 100755 index 0000000..6de01dd --- /dev/null +++ b/src/DatedName.h @@ -0,0 +1,29 @@ +#ifndef DATED_NAME_H +#define DATED_NAME_H + +#include <time.h> +#include "Defines.h" +#include "TimeUnit.h" + +extern const char *datedNameStrings[]; +extern const int datePartLen[]; + +class DatedName { + + public: + bool ProcessName(TimeUnit *freq); + bool ProcessNameLoose(TimeUnit *freq); + void SetNameStr(const char *nameStr); + void UpdateName(tm *ptm); + char *GetName() { return inUseName; } + + private: + SUPPORTED_TIME_UNITS resolution; + char inUseName[CONFIG_MAX_LEN]; + char *timeParts[TIME_UNIT_QTY]; + bool inUseTimeParts[TIME_UNIT_QTY]; + + +}; + +#endif diff --git a/src/Defines.h b/src/Defines.h new file mode 100755 index 0000000..bdb723c --- /dev/null +++ b/src/Defines.h @@ -0,0 +1,39 @@ +#ifndef DEFINES_H +#define DEFINES_H + +#define EF5_VERSION "1.0" + +#define CONFIG_MAX_LEN 256 + +#define TOLOWER(x) for (char *s = x; *s; s++) *s = tolower(*s); +#define TORADIANS(x) (x)/180 * 3.1415926 +#define TODEGREES(x) (x)/3.1415926 * 180 +#define PI 3.1415926 + +//This is here because both grids & projections need to know about it! +/* +enum FLOW_DIR { + FLOW_NORTH = 1, + FLOW_NORTHEAST, + FLOW_EAST, + FLOW_SOUTHEAST, + FLOW_SOUTH, + FLOW_SOUTHWEST, + FLOW_WEST, + FLOW_NORTHWEST, + FLOW_QTY, +};*/ + +enum FLOW_DIR { + FLOW_EAST = 1, + FLOW_NORTHEAST, + FLOW_NORTH, + FLOW_NORTHWEST, + FLOW_WEST, + FLOW_SOUTHWEST, + FLOW_SOUTH, + FLOW_SOUTHEAST, + FLOW_QTY, +}; + +#endif diff --git a/src/DistancePerTimeUnits.cpp b/src/DistancePerTimeUnits.cpp new file mode 100755 index 0000000..753e2fa --- /dev/null +++ b/src/DistancePerTimeUnits.cpp @@ -0,0 +1,33 @@ +#include <cstring> +#include "Defines.h" +#include "DistancePerTimeUnits.h" + + +bool DistancePerTimeUnits::ParseUnit(char *units) { + char distance[CONFIG_MAX_LEN]; + char *timeStr = units; + size_t len = strlen(units); + + // This processes something in the format of distance/time + // It splits up the distance portion from the time portion allowing each to be individually parsed + for (size_t i = 0; i < len; i++) { + if (*timeStr != '/') { + distance[i] = *timeStr; + timeStr++; + } else { + distance[i] = 0; + timeStr++; //Move past the / + break; + } + } + + SUPPORTED_DISTANCE_UNITS distResult = dist.ParseUnit(distance); + SUPPORTED_TIME_UNITS timeResult = time.ParseUnit(timeStr); + + if (distResult == DIST_UNIT_QTY || timeResult == TIME_UNIT_QTY) { + return false; + } else { + return true; + } +} + diff --git a/src/DistancePerTimeUnits.h b/src/DistancePerTimeUnits.h new file mode 100755 index 0000000..03d9599 --- /dev/null +++ b/src/DistancePerTimeUnits.h @@ -0,0 +1,20 @@ +#ifndef DISTANCEPERTIMEUNITS_H +#define DISTANCEPERTIMEUNITS_H + +#include "DistanceUnit.h" +#include "TimeUnit.h" + +class DistancePerTimeUnits { + + public: + bool ParseUnit(char *units); + TimeUnit *GetTime() { return &time; } + DistanceUnit *GetDist() { return &dist; } + + private: + DistanceUnit dist; + TimeUnit time; + +}; + +#endif diff --git a/src/DistanceUnit.cpp b/src/DistanceUnit.cpp new file mode 100755 index 0000000..9c0eeae --- /dev/null +++ b/src/DistanceUnit.cpp @@ -0,0 +1,18 @@ +#include <cstring> +#include "DistanceUnit.h" + +const char *DistanceUnitText[] = { + "m", + "mm", + "cm", +}; + +SUPPORTED_DISTANCE_UNITS DistanceUnit::ParseUnit(char *unitText) { + for (int i = 0; i < DIST_UNIT_QTY; i++) { + if (!strcasecmp(DistanceUnitText[i], unitText)) { + return (SUPPORTED_DISTANCE_UNITS)i; + } + } + + return DIST_UNIT_QTY; +} diff --git a/src/DistanceUnit.h b/src/DistanceUnit.h new file mode 100755 index 0000000..b86d0cf --- /dev/null +++ b/src/DistanceUnit.h @@ -0,0 +1,19 @@ +#ifndef DISTANCEUNIT_H +#define DISTANCEUNIT_H + +enum SUPPORTED_DISTANCE_UNITS { + METERS, + MILLIMETERS, + CENTIMETERS, + DIST_UNIT_QTY, +}; + +extern const char *DistanceUnitText[]; + +class DistanceUnit { + + public: + SUPPORTED_DISTANCE_UNITS ParseUnit(char *unitText); +}; + +#endif diff --git a/src/EF5.cpp b/src/EF5.cpp new file mode 100755 index 0000000..c0c4056 --- /dev/null +++ b/src/EF5.cpp @@ -0,0 +1,63 @@ +#include <cstdio> +#include <unistd.h> + +#include "Defines.h" +#include "Config.h" +#include "ExecutionController.h" +#include "DEMProcessor.h" +#include "EF5.h" + +extern Config *g_config; + +void PrintStartupMessage(); + +int main(int argc, char *argv[]) { + + PrintStartupMessage(); + + if (argc <= 2) { + + g_config = new Config((argc == 2) ? argv[1] : "control.txt"); + if (g_config->ParseConfig() != CONFIG_SUCCESS) { + return 1; + } + + ExecuteTasks(); + } else { + int opt = 0; + int mode = 0; + char *demFile = NULL, *flowDirFile = NULL, *flowAccFile = NULL; + while ((opt = getopt(argc, argv, "z:d:a:ps")) != -1) { + switch (opt) { + case 'z': + demFile = optarg; + break; + case 'd': + flowDirFile = optarg; + break; + case 'a': + flowAccFile = optarg; + break; + case 'p': + mode = 1; + break; + case 's': + mode = 2; + break; + } + } + ProcessDEM(mode, demFile, flowDirFile, flowAccFile); + + } + + return ERROR_SUCCESS; +} + +void PrintStartupMessage() { + printf("%s", "********************************************************\n"); + printf("%s", "** Ensemble Framework For Flash Flood Forecasting **\n"); + printf( "** Version %s **\n", EF5_VERSION); + printf("%s", "********************************************************\n"); + +} + diff --git a/src/EF5.h b/src/EF5.h new file mode 100755 index 0000000..91afcf4 --- /dev/null +++ b/src/EF5.h @@ -0,0 +1,10 @@ +#ifndef EF5_H +#define EF5_H + +enum PROGRAM_RESULTS { + ERROR_SUCCESS, + ERROR_INVALIDCONF, +}; + + +#endif diff --git a/src/EF5Windows.cpp b/src/EF5Windows.cpp new file mode 100755 index 0000000..de79ed9 --- /dev/null +++ b/src/EF5Windows.cpp @@ -0,0 +1,373 @@ +#include <cstdio> +#include <windows.h> +#include <richedit.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <process.h> +#include <time.h> +#include "Defines.h" +#include "Config.h" +#include "ExecutionController.h" +#include "EF5Windows.h" + +#define COLOR_WHITE 0xFFFFFF +#define COLOR_GREY 0xC0C0C0 +#define COLOR_BLUE 0x734D26 +#define COLOR_GREEN 0x4D7326 +#define COLOR_RED 0x262673 +#define COLOR_YELLOW 0x267373 +#define COLOR_PURPLE 0x732673 +#define COLOR_BLUEGREEN 0x737326 +#define COLOR_MIDBLUE 0xA16B36 +#define COLOR_DARKBLUE 0x732626 +#define COLOR_DARKGREEN 0x267326 +#define COLOR_DARKYELLOW 0x264D73 +#define COLOR_DARKRED 0x4D2673 +#define COLOR_DARKPURPLE 0x73264D +#define COLOR_LIGHTBLUE 0xC48A4F + +int CreateWindows(HINSTANCE hInstance); +void DestroyWindows(); +void AddText(const char *szFmt, ...); +void SetColor(COLORREF Color); +void TimeStamp(); + +extern Config *g_config; + +static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +static LRESULT CALLBACK InfoSubclass(HWND Edit, UINT uMsg, WPARAM wParam, LPARAM lParam); +static void PrintStartupMessage(); +static void threadProc(PVOID params); +static DWORD CALLBACK editStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb); + +HANDLE hThread = NULL; +HWND hMainWindow = NULL, hInfo = NULL, hTime = NULL; +WNDCLASSEX wcex; +WNDPROC wpInfo = NULL; +HINSTANCE hREDLL = NULL; +COLORREF CColor = 0; +HINSTANCE hProgram = NULL; +char szTxtToAppend[4096] = ""; +size_t textToAppendSize = 0; +unsigned long sizeOfTextToAppend = 0; +static void MsgLoop(); +int g_iStopLoop = 0; +extern HANDLE hWaitObject; + +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { + int result = EF5_ERROR_SUCCESS; + if (!CreateWindows(hInstance)) { + MessageBox(0, "Failed to create the needed windows.", "EF5", MB_ICONERROR); + return EF5_ERROR_INVALIDCONF; + } + PrintStartupMessage(); + _putenv("TZ=UTC"); + _tzset(); + g_config = new Config((lpszArgument[0]) ? lpszArgument : "control.txt"); + if (g_config->ParseConfig() != CONFIG_SUCCESS) { + result = EF5_ERROR_INVALIDCONF; + } else { + hThread = (HANDLE)_beginthread(threadProc, 0, NULL); + } + MsgLoop(); + DestroyWindows(); + (void)hPrevInstance; + (void)lpszArgument; + (void)nFunsterStil; + return result; +} + +static void MsgLoop() { + while(!g_iStopLoop) { + if(MsgWaitForMultipleObjectsEx(0, 0, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE) == WAIT_OBJECT_0) { + MSG msg; + while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } +} + +int CreateWindows(HINSTANCE hInstance) { + PARAFORMAT2 pf; + CHARFORMAT cfFormat; + hREDLL = LoadLibrary("RichEd32.dll"); + if (!hREDLL) + return 0; + hProgram = hInstance; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)MainWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)COLOR_BACKGROUND; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = "EF5Class"; + wcex.hIconSm = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); + if (!RegisterClassEx(&wcex)) { + FreeLibrary(hREDLL); + return 0; + } + hMainWindow = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_OVERLAPPEDWINDOW, "EF5Class", "Ensemble Framework For Flash Flood Forecasting", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT , CW_USEDEFAULT, NULL, NULL, hInstance, NULL); + if (!hMainWindow) { + UnregisterClass("EF5Class", hInstance); + FreeLibrary(hREDLL); + return 0; + } + hInfo = CreateWindowEx(0, RICHEDIT_CLASS, "", WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL | ES_READONLY, 20, 20, 290, 120, hMainWindow, NULL, hInstance, NULL); + if (!hInfo) { + DestroyWindow(hMainWindow); + UnregisterClass("EF5Class", hInstance); + FreeLibrary(hREDLL); + return 0; + } + hTime = CreateWindowEx(WS_EX_TRANSPARENT, "STATIC", "", WS_CHILD , 20, 20, 290, 120, hMainWindow, NULL, hInstance, NULL); + if (!hTime) { + DestroyWindow(hMainWindow); + UnregisterClass("EF5Class", hInstance); + FreeLibrary(hREDLL); + return 0; + } + SendMessage(hTime, WM_SETTEXT, NULL, (LPARAM)"Current Timestep: "); + + //hSend = CreateWindowEx(0, RICHEDIT_CLASS, "", WS_CHILD , 20, 180, 290, 30, hMainWindow, NULL, hInstance, NULL); + //if (!hSend) { +// return 0; +// } + pf.cbSize = sizeof(PARAFORMAT2); + SendMessage(hInfo, EM_GETPARAFORMAT, 0, (LPARAM)&pf); + pf.dwMask = PFM_OFFSET; + pf.dxOffset = 1120; + SendMessage(hInfo, EM_SETPARAFORMAT, 0, (LPARAM)&pf); + SendMessage(hInfo, EM_AUTOURLDETECT, TRUE, 0); + SendMessage(hInfo, EM_SETEVENTMASK, 0, ENM_LINK); + SendMessage(hInfo, EM_SETBKGNDCOLOR, FALSE, 0x00000000); +// SendMessage(hSend, EM_SETBKGNDCOLOR, FALSE, 0x00000000); + cfFormat.cbSize = sizeof(CHARFORMAT); + cfFormat.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE; + cfFormat.dwEffects = CFE_PROTECTED; + cfFormat.yHeight = 190; + cfFormat.yOffset = 0; + cfFormat.crTextColor = COLOR_WHITE; + cfFormat.bCharSet = DEFAULT_CHARSET; + cfFormat.bPitchAndFamily = DEFAULT_PITCH; + strncpy(cfFormat.szFaceName, "Tahoma", 31); + cfFormat.szFaceName[31] = 0; +// SendMessage(hSend, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cfFormat); +// SendMessage(hSend, EM_EXLIMITTEXT, (WPARAM)0, (LPARAM)200); + wpInfo = (WNDPROC)(LONG_PTR)SetWindowLong(hInfo, GWLP_WNDPROC, (LONG)(LONG_PTR)InfoSubclass); +// wpSend = (WNDPROC)(LONG_PTR)SetWindowLong(hSend, GWL_WNDPROC, (LONG)(LONG_PTR)SendSubclass); + ShowWindow(hMainWindow, SW_SHOWNORMAL); + ShowWindow(hInfo, SW_SHOWNORMAL); + ShowWindow(hTime, SW_SHOWNORMAL); + return 1; +} + +void DestroyWindows() { + SetWindowLong(hInfo, GWLP_WNDPROC, (LONG)(LONG_PTR)wpInfo); + //SetWindowLong(hSend, GWL_WNDPROC, (LONG)(LONG_PTR)wpSend); + DestroyWindow(hMainWindow); //Children get killed automatically + UnregisterClass("EF5Class", hProgram); + FreeLibrary(hREDLL); +} + +static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_CLOSE: { + g_iStopLoop = 1; + return 0; + } + case WM_SIZE: { + RECT mainw = {0}, infow = {0}; + GetClientRect(hMainWindow, &mainw ); + SetWindowPos(hInfo, NULL, 20, 20, mainw.right - 40, mainw.bottom - 40, SWP_NOACTIVATE | SWP_NOZORDER); + SetWindowPos(hTime, NULL, 20, 3, mainw.right - 40, 15, SWP_NOACTIVATE | SWP_NOZORDER); + return 0; + } + case WM_CREATE: { + return 0; + } + default: { + return DefWindowProc( hWnd, message, wParam, lParam ); + } + } +} + +static LRESULT CALLBACK InfoSubclass(HWND Edit, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_KEYDOWN: + case WM_CHAR: { + if (wParam == 'C' && (GetKeyState(VK_CONTROL) & 0x8000)) + return CallWindowProc( wpInfo, Edit, uMsg, wParam, lParam ); + return 0; + } + default: { + return CallWindowProc( wpInfo, Edit, uMsg, wParam, lParam ); + } + } +} + +void AddText(const char *szFmt, ...) { + LONG linecount2 = 0; //, linecount2 = 0; + SCROLLINFO SI; + CHARFORMAT cfFormat; + POINT p; + CHARRANGE Range = {-1, -1}, Range2 = {-1, -1}, Range3 = {-1, -1}; + EDITSTREAM editStream; + va_list vaArg; + va_start(vaArg, szFmt); + _vsnprintf(szTxtToAppend, 4096, szFmt, vaArg); + va_end(vaArg); + szTxtToAppend[4095] = 0; + textToAppendSize = strlen(szTxtToAppend); + //if (nStopLoop == 1) + // return; + ZeroMemory(&SI, sizeof(SI)); + SI.cbSize = sizeof(SI); + SI.fMask = 7; + cfFormat.cbSize = sizeof(CHARFORMAT); + cfFormat.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_BOLD; + cfFormat.dwEffects = CFE_PROTECTED; + cfFormat.yHeight = 190; + cfFormat.yOffset = 0; + cfFormat.crTextColor = CColor; + cfFormat.bCharSet = DEFAULT_CHARSET; + cfFormat.bPitchAndFamily = DEFAULT_PITCH; + strncpy(cfFormat.szFaceName, "Tahoma", 32); + cfFormat.szFaceName[31] = 0; + SendMessage(hInfo, WM_SETREDRAW, 0, 0); + SendMessage(hInfo, EM_GETSCROLLPOS, 0, (LPARAM)&p); + GetScrollInfo(hInfo, SB_VERT, &SI); + //linecount = (LONG)SendMessage(hInfo, EM_GETLINECOUNT, 0, 0); + SendMessage(hInfo, EM_EXGETSEL, 0, (LPARAM)&Range); + SendMessage(hInfo, EM_EXSETSEL, 0, (LPARAM)&Range2); + SendMessage(hInfo, EM_EXGETSEL, 0, (LPARAM)&Range3); + SendMessage(hInfo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfFormat); + editStream.dwCookie = 0; + editStream.dwError = 0; + editStream.pfnCallback = editStreamCallback; + SendMessage(hInfo, EM_STREAMIN, SF_TEXT | SFF_SELECTION, (LPARAM)&editStream); + linecount2 = (LONG)SendMessage(hInfo, EM_GETLINECOUNT, 0, 0); + if (linecount2 > 2000) { + Range2.cpMin = 0; + Range2.cpMax = (LONG)SendMessage(hInfo, EM_LINEINDEX, 1, 0); + SendMessage(hInfo, EM_EXSETSEL, 0, (LPARAM)&Range2); + SendMessage(hInfo, EM_REPLACESEL, 0, (LPARAM)""); + Range.cpMin -= Range2.cpMax; + Range.cpMax -= Range2.cpMax; + } + SendMessage(hInfo, EM_EXSETSEL, 0, (LPARAM)&Range); + SendMessage(hInfo, EM_SETSCROLLPOS, 0, (LPARAM)&p); + + //if(linecount == 1 || SI.nMax == SI.nPos + (int)SI.nPage) { + SendMessage(hInfo, WM_VSCROLL, SB_BOTTOM, 0); + //} else if (linecount2 > 2000) { + // SendMessage(hInfo, EM_LINESCROLL, 0, -1); + //} + SendMessage(hInfo, WM_SETREDRAW, 1, 0); + InvalidateRect(hInfo, 0, 1); +} + +static DWORD CALLBACK editStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb) { + *pcb = cb; + if (*pcb > (LONG)textToAppendSize) { + *pcb = (LONG)textToAppendSize; + } + if (*pcb > 0) { + memcpy(pbBuff, szTxtToAppend, *pcb); + textToAppendSize -= *pcb; + } + return 0; + (void)dwCookie; +} + +void SetColor(COLORREF Color) { + CColor = Color; +} + +void TimeStamp() { + SYSTEMTIME st; + GetLocalTime(&st); + SetColor(COLOR_WHITE); + AddText("[%02i:%02i:%02i] ", st.wHour, st.wMinute, st.wSecond); +} + +void addConsoleText(CONSOLEMESSAGETYPE type, const char *szFmt, ...) { + char txtToAppend[4096] = ""; + va_list vaArg; + va_start(vaArg, szFmt); + _vsnprintf(txtToAppend, 4096, szFmt, vaArg); + va_end(vaArg); + szTxtToAppend[4095] = 0; + //TimeStamp(); + switch (type) { + case NORMAL: + SetColor(COLOR_LIGHTBLUE); + AddText("%s", txtToAppend); + break; + case INFORMATION: + SetColor(COLOR_GREEN); + AddText("%s", "INFO: "); + SetColor(COLOR_WHITE); + AddText("%s\n", txtToAppend); + break; + case WARNING: + SetColor(COLOR_YELLOW); + AddText("%s", "WARNING: "); + SetColor(COLOR_WHITE); + AddText("%s\n", txtToAppend); + break; + case FATAL: + SetColor(COLOR_RED); + AddText("%s", "ERROR: "); + SetColor(COLOR_WHITE); + AddText("%s\n", txtToAppend); + break; + } +} + +void setTimestep(const char *szTime) { + char txt[4096] = ""; + sprintf(txt, "Current Timestep: %s", szTime); + SendMessage(hTime, WM_SETTEXT, NULL, (LPARAM)txt); +} + +void setIteration(int current) { + char txt[4096] = ""; + sprintf(txt, "Current Iteration: %i", current); + SendMessage(hTime, WM_SETTEXT, NULL, (LPARAM)txt); +} + +/*int main(int argc, char *argv[]) { + + PrintStartupMessage(); + + g_config = new Config((argc == 2) ? argv[1] : "control.txt"); + if (g_config->ParseConfig() != CONFIG_SUCCESS) { + return 1; + } + + ExecuteTasks(); + + return ERROR_SUCCESS; +}*/ + +void PrintStartupMessage() { + addConsoleText(NORMAL, "%s", "********************************************************\n"); + addConsoleText(NORMAL, "%s", "** Ensemble Framework For Flash Flood Forecasting **\n"); + addConsoleText(NORMAL, "** Version %s **\n", EF5_VERSION); + addConsoleText(NORMAL,"%s", "********************************************************\n"); + +} + +static void threadProc(PVOID params) { + _putenv("TZ=UTC"); + _tzset(); + ExecuteTasks(); + addConsoleText(NORMAL, "%s", "Done!\n"); +} diff --git a/src/EF5Windows.h b/src/EF5Windows.h new file mode 100755 index 0000000..9af18cf --- /dev/null +++ b/src/EF5Windows.h @@ -0,0 +1,20 @@ +#ifndef EF5WINDOWS_H +#define EF5WINDOWS_H + +enum PROGRAM_RESULTS { + EF5_ERROR_SUCCESS = 0, + EF5_ERROR_INVALIDCONF +}; + +enum CONSOLEMESSAGETYPE { + NORMAL = 0, + INFORMATION = 1, + WARNING = 2, + FATAL = 3, +}; + +void addConsoleText(CONSOLEMESSAGETYPE type, const char *szFmt, ...); +void setTimestep(const char *szTime); +void setIteration(int current); + +#endif diff --git a/src/EnsTaskConfigSection.cpp b/src/EnsTaskConfigSection.cpp new file mode 100755 index 0000000..8148c62 --- /dev/null +++ b/src/EnsTaskConfigSection.cpp @@ -0,0 +1,72 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "EnsTaskConfigSection.h" + +std::map<std::string, EnsTaskConfigSection *> g_ensTaskConfigs; + +EnsTaskConfigSection::EnsTaskConfigSection(const char *nameVal) { + strcpy(name, nameVal); + styleSet = false; +} + +EnsTaskConfigSection::~EnsTaskConfigSection() { + +} + +char *EnsTaskConfigSection::GetName() { + return name; +} + +RUNSTYLE EnsTaskConfigSection::GetRunStyle() { + return style; +} + +CONFIG_SEC_RET EnsTaskConfigSection::ProcessKeyValue(char *name, char *value) { + if (!strcasecmp(name, "style")) { + for (int i = 0; i < STYLE_QTY; i++) { + if (!strcasecmp(value, runStyleStrings[i])) { + styleSet = true; + style = (RUNSTYLE)i; + return VALID_RESULT; + } + } + ERROR_LOGF("Unknown run style option \"%s\"!", value); + return INVALID_RESULT; + } else if (strcasecmp(name, "task") == 0) { + TOLOWER(value); + std::map<std::string, TaskConfigSection *>::iterator itr = g_taskConfigs.find(value); + if (itr == g_taskConfigs.end()) { + ERROR_LOGF("Unknown task \"%s\" in basin!", value); + return INVALID_RESULT; + } + tasks.push_back(itr->second); + } else { + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +CONFIG_SEC_RET EnsTaskConfigSection::ValidateSection() { + + if (tasks.size() == 0) { + ERROR_LOG("No tasks were defined!"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +std::vector<TaskConfigSection *> *EnsTaskConfigSection::GetTasks() { + return &tasks; +} + +bool EnsTaskConfigSection::IsDuplicate(char *name) { + std::map<std::string, EnsTaskConfigSection *>::iterator itr = g_ensTaskConfigs.find(name); + if (itr == g_ensTaskConfigs.end()) { + return false; + } else { + return true; + } +} diff --git a/src/EnsTaskConfigSection.h b/src/EnsTaskConfigSection.h new file mode 100755 index 0000000..53934b3 --- /dev/null +++ b/src/EnsTaskConfigSection.h @@ -0,0 +1,35 @@ +#ifndef CONFIG_ENSTASKCONFIG_SECTION_H +#define CONFIG_ENSTASKCONFIG_SECTION_H + +#include <vector> +#include <string> +#include "Defines.h" +#include "ConfigSection.h" +#include "TaskConfigSection.h" + +class EnsTaskConfigSection : public ConfigSection { + + public: + EnsTaskConfigSection(const char *nameVal); + ~EnsTaskConfigSection(); + + char *GetName(); + RUNSTYLE GetRunStyle(); + + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + std::vector<TaskConfigSection *> *GetTasks(); + + static bool IsDuplicate(char *name); + + private: + bool styleSet; + char name[CONFIG_MAX_LEN]; + RUNSTYLE style; + std::vector<TaskConfigSection *> tasks; +}; + +extern std::map<std::string, EnsTaskConfigSection *> g_ensTaskConfigs; + +#endif diff --git a/src/ExecuteConfigSection.cpp b/src/ExecuteConfigSection.cpp new file mode 100755 index 0000000..3b1814e --- /dev/null +++ b/src/ExecuteConfigSection.cpp @@ -0,0 +1,54 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "ExecuteConfigSection.h" + +ExecuteConfigSection *g_executeConfig = NULL; + +ExecuteConfigSection::ExecuteConfigSection() { +} + +ExecuteConfigSection::~ExecuteConfigSection() { + +} + +CONFIG_SEC_RET ExecuteConfigSection::ProcessKeyValue(char *name, char *value) { + if (strcasecmp(name, "task") == 0) { + TOLOWER(value); + std::map<std::string, TaskConfigSection *>::iterator itr = g_taskConfigs.find(value); + if (itr == g_taskConfigs.end()) { + ERROR_LOGF("Unknown task \"%s\"!", value); + return INVALID_RESULT; + } + tasks.push_back(itr->second); + } else if (strcasecmp(name, "ensembletask") == 0) { + TOLOWER(value); + std::map<std::string, EnsTaskConfigSection *>::iterator itr = g_ensTaskConfigs.find(value); + if (itr == g_ensTaskConfigs.end()) { + ERROR_LOGF("Unknown ensemble task \"%s\"!", value); + return INVALID_RESULT; + } + ensTasks.push_back(itr->second); + } else { + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +CONFIG_SEC_RET ExecuteConfigSection::ValidateSection() { + if (tasks.size() == 0) { + ERROR_LOG("No tasks were defined!"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +std::vector<TaskConfigSection *> *ExecuteConfigSection::GetTasks() { + return &tasks; +} + +std::vector<EnsTaskConfigSection *> *ExecuteConfigSection::GetEnsTasks() { + return &ensTasks; +} diff --git a/src/ExecuteConfigSection.h b/src/ExecuteConfigSection.h new file mode 100755 index 0000000..cea71d6 --- /dev/null +++ b/src/ExecuteConfigSection.h @@ -0,0 +1,30 @@ +#ifndef CONFIG_EXECUTE_SECTION_H +#define CONFIG_EXECUTE_SECTION_H + +#include <vector> +#include <string> +#include "Defines.h" +#include "ConfigSection.h" +#include "EnsTaskConfigSection.h" +#include "TaskConfigSection.h" + + +class ExecuteConfigSection : public ConfigSection { + + public: + ExecuteConfigSection(); + ~ExecuteConfigSection(); + + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + std::vector<TaskConfigSection *> *GetTasks(); + std::vector<EnsTaskConfigSection *> *GetEnsTasks(); + private: + std::vector<TaskConfigSection *> tasks; + std::vector<EnsTaskConfigSection *> ensTasks; +}; + +extern ExecuteConfigSection *g_executeConfig; + +#endif diff --git a/src/ExecutionController.cpp b/src/ExecutionController.cpp new file mode 100755 index 0000000..e4768a9 --- /dev/null +++ b/src/ExecutionController.cpp @@ -0,0 +1,300 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "BasicConfigSection.h" +#include "BasinConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" +#include "EnsTaskConfigSection.h" +#include "TaskConfigSection.h" +#include "ExecuteConfigSection.h" +#include "GeographicProjection.h" +#include "LAEAProjection.h" +#include "TimeVar.h" +#include "BasicGrids.h" +#include "ARS.h" +#include "DREAM.h" +#include "Simulator.h" +#include "ExecutionController.h" + +static void LoadProjection(); +static void ExecuteSimulation(TaskConfigSection *task); +static void ExecuteSimulationRP(TaskConfigSection *task); +static void ExecuteCalibrationARS(TaskConfigSection *task); +static void ExecuteCalibrationDREAM(TaskConfigSection *task); +static void ExecuteCalibrationDREAMEns(EnsTaskConfigSection *task); +static void ExecuteClipBasin(TaskConfigSection *task); +static void ExecuteClipGauge(TaskConfigSection *task); +static void ExecuteMakeBasic(TaskConfigSection *task); +static void ExecuteMakeBasinAvg(TaskConfigSection *task); + +void ExecuteTasks() { + + if (!g_executeConfig) { + ERROR_LOGF("%s", "No execute section specified!"); + return; + } + + std::vector<TaskConfigSection *> *tasks = g_executeConfig->GetTasks(); + std::vector<TaskConfigSection *>::iterator taskItr; + + std::vector<EnsTaskConfigSection *> *ensTasks = g_executeConfig->GetEnsTasks(); + std::vector<EnsTaskConfigSection *>::iterator ensTaskItr; + + if (!LoadBasicGrids()) { + return; + } + LoadProjection(); + + // Loop through all the ensemble tasks and execute them first + for (ensTaskItr = ensTasks->begin(); ensTaskItr != ensTasks->end(); ensTaskItr++) { + EnsTaskConfigSection *ensTask = (*ensTaskItr); + INFO_LOGF("Executing ensemble task %s", ensTask->GetName()); + + switch (ensTask->GetRunStyle()) { + case STYLE_CALI_DREAM: + ExecuteCalibrationDREAMEns(ensTask); + break; + default: + ERROR_LOGF("Unsupport ensemble task run style \"%u\"", ensTask->GetRunStyle()); + break; + } + } + + //Loop through all of the tasks and execute them + for (taskItr = tasks->begin(); taskItr != tasks->end(); taskItr++) { + TaskConfigSection *task = (*taskItr); + INFO_LOGF("Executing task %s", task->GetName()); + + switch (task->GetRunStyle()) { + case STYLE_SIMU: + ExecuteSimulation(task); + break; + case STYLE_SIMU_RP: + ExecuteSimulationRP(task); + break; + case STYLE_CALI_ARS: + ExecuteCalibrationARS(task); + break; + case STYLE_CALI_DREAM: + ExecuteCalibrationDREAM(task); + break; + case STYLE_CLIP_BASIN: + ExecuteClipBasin(task); + break; + case STYLE_CLIP_GAUGE: + ExecuteClipGauge(task); + break; + case STYLE_MAKE_BASIC: + ExecuteMakeBasic(task); + break; + case STYLE_BASIN_AVG: + ExecuteMakeBasinAvg(task); + default: + ERROR_LOGF("Unimplemented simulation run style \"%u\"", task->GetRunStyle()); + break; + } + + } + + FreeBasicGridsData(); +} + +void LoadProjection() { + + switch (g_basicConfig->GetProjection()) { + case PROJECTION_GEOGRAPHIC: + g_Projection = new GeographicProjection(); + g_Projection->SetCellSize(g_DEM->cellSize); + break; + case PROJECTION_LAEA: + g_Projection = new LAEAProjection(); + g_Projection->SetCellSize(g_DEM->cellSize); + break; + } + + //Reproject the gauges into the proper map coordinates + for (std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.begin(); itr != g_gaugeConfigs.end(); itr++) { + + GaugeConfigSection *gauge = itr->second; + float newX, newY; + g_Projection->ReprojectPoint(gauge->GetLon(), gauge->GetLat(), &newX, &newY); + gauge->SetLon(newX); + gauge->SetLat(newY); + } + +} + +void ExecuteSimulation(TaskConfigSection *task) { + + Simulator sim; + + if (sim.Initialize(task)) { + sim.Simulate(); + sim.CleanUp(); + } +} + +void ExecuteSimulationRP(TaskConfigSection *task) { + + Simulator sim; + + sim.Initialize(task); + sim.Simulate(true); + sim.CleanUp(); +} + +void ExecuteCalibrationARS(TaskConfigSection *task) { + + Simulator sim; + char buffer[CONFIG_MAX_LEN*2]; + + sim.Initialize(task); + sprintf(buffer, "%s/%s", task->GetOutput(), "califorcings.bin"); + sim.PreloadForcings(buffer, true); + + printf("Precip loaded!\n"); + + ARS ars; + ars.Initialize(task->GetCaliParamSec(), task->GetRoutingCaliParamSec(), NULL, numModelParams[task->GetModel()], numRouteParams[task->GetRouting()], 0, &sim); + ars.CalibrateParams(); + + + sprintf(buffer, "%s/cali_ars.%s.%s.csv", task->GetOutput(), task->GetCaliParamSec()->GetGauge()->GetName(), modelStrings[task->GetModel()]); + ars.WriteOutput(buffer, task->GetModel(), task->GetRouting()); + +} + +void ExecuteCalibrationDREAM(TaskConfigSection *task) { + + Simulator sim; + char buffer[CONFIG_MAX_LEN*2]; + + sim.Initialize(task); + sprintf(buffer, "%s/%s", task->GetOutput(), "califorcings.bin"); + sim.PreloadForcings(buffer, true); + + INFO_LOGF("%s","Precip loaded!"); + + DREAM dream; + int numSnow = 0; + if (task->GetSnow() != SNOW_QTY) { + numSnow = numSnowParams[task->GetSnow()]; + } + dream.Initialize(task->GetCaliParamSec(), task->GetRoutingCaliParamSec(), task->GetSnowCaliParamSec(), numModelParams[task->GetModel()], numRouteParams[task->GetRouting()], numSnow, &sim); + dream.CalibrateParams(); + + + sprintf(buffer, "%s/cali_dream.%s.%s.csv", task->GetOutput(), task->GetCaliParamSec()->GetGauge()->GetName(), modelStrings[task->GetModel()]); + dream.WriteOutput(buffer, task->GetModel(), task->GetRouting(), task->GetSnow()); + +} + +void ExecuteCalibrationDREAMEns(EnsTaskConfigSection *task) { + + char buffer[CONFIG_MAX_LEN*2]; + std::vector<TaskConfigSection *> *tasks = task->GetTasks(); + int numMembers = tasks->size(); + int numParams = 0; + + std::vector<Simulator> sims; + std::vector<int> paramsPerSim; + paramsPerSim.resize(numMembers); + sims.resize(numMembers); + + for (int i = 0; i < numMembers; i++) { + Simulator *sim = &(sims[i]); + TaskConfigSection *thisTask = tasks->at(i); + sim->Initialize(thisTask); + sprintf(buffer, "%s/%s", thisTask->GetOutput(), "califorcings.bin"); + sim->PreloadForcings(buffer, true); + numParams += numModelParams[thisTask->GetModel()]; + paramsPerSim[i] = numModelParams[thisTask->GetModel()]; + } + + float *minParams = new float[numParams]; + float *maxParams = new float[numParams]; + int paramIndex = 0; + + for (int i = 0; i < numMembers; i++) { + TaskConfigSection *thisTask = tasks->at(i); + int cParams = numModelParams[thisTask->GetModel()]; + memcpy(&(minParams[paramIndex]), thisTask->GetCaliParamSec()->GetParamMins(), sizeof(float)*cParams); + memcpy(&(maxParams[paramIndex]), thisTask->GetCaliParamSec()->GetParamMaxs(), sizeof(float)*cParams); + paramIndex += cParams; + } + + INFO_LOGF("%s", "Precip loaded!\n"); + + DREAM dream; + dream.Initialize(tasks->at(0)->GetCaliParamSec(), numParams, minParams, maxParams, &sims, ¶msPerSim); + dream.CalibrateParams(); + + + sprintf(buffer, "%s/cali_dream.%s.%s.csv", tasks->at(0)->GetOutput(), tasks->at(0)->GetCaliParamSec()->GetGauge()->GetName(), "ensemble"); + dream.WriteOutput(buffer, tasks->at(0)->GetModel(), tasks->at(0)->GetRouting(), tasks->at(0)->GetSnow()); + +} + +void ExecuteClipBasin(TaskConfigSection *task) { + std::map<GaugeConfigSection *, float *> fullParamSettings, *paramSettings, fullRouteParamSettings, *routeParamSettings; + std::vector<GridNode> nodes; + GaugeMap gaugeMap; + + // Get the parameter settings for this task + paramSettings = task->GetParamsSec()->GetParamSettings(); + float *defaultParams = NULL, *defaultRouteParams = NULL; + GaugeConfigSection *gs = task->GetDefaultGauge(); + std::map<GaugeConfigSection *, float *>::iterator pitr = paramSettings->find(gs); + if (pitr != paramSettings->end()) { + defaultParams = pitr->second; + } + routeParamSettings = task->GetRoutingParamsSec()->GetParamSettings(); + pitr = routeParamSettings->find(gs); + if (pitr != routeParamSettings->end()) { + defaultRouteParams = pitr->second; + } + + CarveBasin(task->GetBasinSec(), &nodes, paramSettings, &fullParamSettings, &gaugeMap, defaultParams, routeParamSettings, &fullRouteParamSettings, defaultRouteParams, NULL, NULL, NULL, NULL, NULL, NULL); + + ClipBasicGrids(task->GetBasinSec(), &nodes, task->GetBasinSec()->GetName(), task->GetOutput()); +} + +void ExecuteClipGauge(TaskConfigSection *task) { + std::map<GaugeConfigSection *, float *> fullParamSettings, *paramSettings, fullRouteParamSettings, *routeParamSettings; + std::vector<GridNode> nodes; + GaugeMap gaugeMap; + + // Get the parameter settings for this task + paramSettings = task->GetParamsSec()->GetParamSettings(); + float *defaultParams = NULL, *defaultRouteParams = NULL; + GaugeConfigSection *gs = task->GetDefaultGauge(); + std::map<GaugeConfigSection *, float *>::iterator pitr = paramSettings->find(gs); + if (pitr != paramSettings->end()) { + defaultParams = pitr->second; + } + routeParamSettings = task->GetRoutingParamsSec()->GetParamSettings(); + pitr = routeParamSettings->find(gs); + if (pitr != routeParamSettings->end()) { + defaultRouteParams = pitr->second; + } + + CarveBasin(task->GetBasinSec(), &nodes, paramSettings, &fullParamSettings, &gaugeMap, defaultParams, routeParamSettings, &fullRouteParamSettings, defaultRouteParams, NULL, NULL, NULL, NULL, NULL, NULL); + + + GridLoc *loc = (*(task->GetBasinSec()->GetGauges()))[0]->GetGridLoc(); + ClipBasicGrids(loc->x, loc->y, 10, task->GetOutput()); +} + +void ExecuteMakeBasic(TaskConfigSection *task) { + MakeBasic(); +} + +void ExecuteMakeBasinAvg(TaskConfigSection *task) { + Simulator sim; + + if (sim.Initialize(task)) { + sim.BasinAvg(); + sim.CleanUp(); + } +} diff --git a/src/ExecutionController.h b/src/ExecutionController.h new file mode 100755 index 0000000..cef0c38 --- /dev/null +++ b/src/ExecutionController.h @@ -0,0 +1,6 @@ +#ifndef EXECUTION_CONTROLLER_H +#define EXECUTION_CONTROLLER_H + +void ExecuteTasks(); + +#endif diff --git a/src/GaugeConfigSection.cpp b/src/GaugeConfigSection.cpp new file mode 100755 index 0000000..d524612 --- /dev/null +++ b/src/GaugeConfigSection.cpp @@ -0,0 +1,144 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <limits> +#include "Messages.h" +#include "GaugeConfigSection.h" + +std::map<std::string, GaugeConfigSection *> g_gaugeConfigs; + +GaugeConfigSection::GaugeConfigSection(char *nameVal) { + obsSet = false; + latSet = false; + lonSet = false; + xSet = false; + ySet = false; + obsFlowAccumSet = false; + strcpy(name, nameVal); + outputTS = true; + observation[0] = 0; + wantDA = true; + wantCO = false; + continueUpstream = true; +} + +GaugeConfigSection::~GaugeConfigSection() { + +} + +char *GaugeConfigSection::GetName() { + return name; +} + +void GaugeConfigSection::LoadTS() { + if (observation[0]) { + obs.LoadTimeSeries(observation); + } +} + +float GaugeConfigSection::GetObserved(TimeVar *currentTime) { + if (!obs.GetNumberOfObs()) { + return std::numeric_limits<float>::quiet_NaN(); + } + return obs.GetValueAtTime(currentTime); +} + +float GaugeConfigSection::GetObserved(TimeVar *currentTime, float diff) { + if (!obs.GetNumberOfObs()) { + return std::numeric_limits<float>::quiet_NaN(); + } + return obs.GetValueNearTime(currentTime, diff); +} + +void GaugeConfigSection::SetObservedValue(char *timeBuffer, float dataValue) { + obs.PutValueAtTime(timeBuffer, dataValue); +} + +CONFIG_SEC_RET GaugeConfigSection::ProcessKeyValue(char *name, char *value) { + + if (!strcasecmp(name, "lat")) { + lat = strtod(value, NULL); + latSet = true; + } else if (!strcasecmp(name, "lon")) { + lon = strtod(value, NULL); + lonSet = true; + } else if (!strcasecmp(name, "cellx")) { + SetCellX(atoi(value)); + xSet = true; + } else if (!strcasecmp(name, "celly")) { + SetCellY(atoi(value)); + ySet = true; + } else if (!strcasecmp(name, "basinarea")) { + obsFlowAccum = atof(value); + obsFlowAccumSet = true; + } else if (!strcasecmp(name, "obs")) { + strcpy(observation, value); + obsSet = true; + } else if (!strcasecmp(name, "outputts")) { + if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) { + outputTS = false; + } else if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) { + outputTS = true; + } else { + ERROR_LOGF("Unknown OUTPUTTS option \"%s\"", value); + INFO_LOGF("Valid OUTPUTTS options are \"%s\"", "TRUE, FALSE"); + return INVALID_RESULT; + } + outputTSSet = true; + } else if (!strcasecmp(name, "wantda")) { + if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) { + wantDA = false; + } else if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) { + wantDA = true; + } else { + ERROR_LOGF("Unknown WANTDA option \"%s\"", value); + INFO_LOGF("Valid WANTDA options are \"%s\"", "TRUE, FALSE"); + return INVALID_RESULT; + } + } else if (!strcasecmp(name, "wantco")) { + if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) { + wantCO = false; + } else if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) { + wantCO = true; + } else { + ERROR_LOGF("Unknown WANTCO option \"%s\"", value); + INFO_LOGF("Valid WANTCO options are \"%s\"", "TRUE, FALSE"); + return INVALID_RESULT; + } + } else if (!strcasecmp(name, "continueupstream")) { + if (!strcasecmp(value, "false") || !strcasecmp(value, "no")) { + continueUpstream = false; + } else if (!strcasecmp(value, "true") || !strcasecmp(value, "yes")) { + continueUpstream = true; + } else { + ERROR_LOGF("Unknown CONTINUEUPSTREAM option \"%s\"", value); + INFO_LOGF("Valid CONTINUEUPSTREAM options are \"%s\"", "TRUE, FALSE"); + return INVALID_RESULT; + } + } else { + ERROR_LOGF("Unknown key value \"%s=%s\" in gauge %s!", name, value, this->name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET GaugeConfigSection::ValidateSection() { + if (!latSet && !ySet) { + ERROR_LOG("The latitude was not specified"); + return INVALID_RESULT; + } else if (!lonSet && !xSet) { + ERROR_LOG("The longitude was not specified"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +bool GaugeConfigSection::IsDuplicate(char *name) { + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(name); + if (itr == g_gaugeConfigs.end()) { + return false; + } else { + return true; + } +} diff --git a/src/GaugeConfigSection.h b/src/GaugeConfigSection.h new file mode 100755 index 0000000..5f2f838 --- /dev/null +++ b/src/GaugeConfigSection.h @@ -0,0 +1,68 @@ +#ifndef CONFIG_GAUGE_SECTION_H +#define CONFIG_GAUGE_SECTION_H + +#include <map> +#include <string> +#include "Defines.h" +#include "Grid.h" +#include "ConfigSection.h" +#include "TimeSeries.h" +#include "TimeVar.h" + +class GaugeConfigSection : public ConfigSection { + + public: + GaugeConfigSection(char *nameVal); + ~GaugeConfigSection(); + + char *GetName(); + float GetLat() { return lat; } + float GetLon() { return lon; } + long GetGridNodeIndex() { return gridNodeIndex; } + bool GetUsed() { return used; } + bool OutputTS() { return outputTS; } + bool WantDA() { return wantDA; } + bool WantCO() { return wantCO; } + bool ContinueUpstream() { return continueUpstream; } + long GetFlowAccum() { return flowAccum; } + bool HasObsFlowAccum() { return obsFlowAccumSet; } + float GetObsFlowAccum() { return obsFlowAccum; } + GridLoc *GetGridLoc() { return &gridLoc; } + float GetObserved(TimeVar *currentTime); + float GetObserved(TimeVar *currentTime, float diff); + void SetObservedValue(char *timeBuffer, float dataValue); + void LoadTS(); + void SetGridNodeIndex(long newVal) { gridNodeIndex = newVal; } + void SetLat(float newVal) { lat = newVal; } + void SetLon(float newVal) { lon = newVal; } + void SetCellX(long newX) { gridLoc.x = newX; } + void SetCellY(long newY) { gridLoc.y = newY; } + void SetUsed(bool newVal) { used = newVal; } + void SetFlowAccum(long newVal) { flowAccum = newVal; } + bool NeedsProjecting() { return latSet; } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name); + + private: + bool obsSet, latSet, lonSet, xSet, ySet, obsFlowAccumSet, outputTSSet; + bool outputTS, wantDA, wantCO, continueUpstream; + char observation[CONFIG_MAX_LEN]; + char name[CONFIG_MAX_LEN]; + float lat; + float lon; + float obsFlowAccum; + TimeSeries obs; + + //These are for basin carving procedures! + long flowAccum; + bool used; + GridLoc gridLoc; + long gridNodeIndex; + +}; + +extern std::map<std::string, GaugeConfigSection *> g_gaugeConfigs; + +#endif diff --git a/src/GaugeMap.cpp b/src/GaugeMap.cpp new file mode 100755 index 0000000..0eb3272 --- /dev/null +++ b/src/GaugeMap.cpp @@ -0,0 +1,112 @@ +#include <cstdio> +#include "GaugeMap.h" + +void GaugeMap::Initialize(std::vector<GaugeConfigSection *> *newGauges) { + // Copy the list of gauges over to internal storage + gauges = (*newGauges); + + size_t countGauges = gauges.size(); + + // Resize the outer vector in the tree that contains all of the interior gauges + gaugeTree.resize(countGauges); + + // Initialize the map that contains the index into a vector for each + // GaugeConfigSection * + for (size_t i = 0; i < countGauges; i++) { + gaugeMap[gauges[i]] = i; + } + + // Initialize storage for the partial values contributing to each gauge + partialVal.resize(countGauges); + partialArea.resize(countGauges); +} + +void GaugeMap::AddUpstreamGauge(GaugeConfigSection *downStream, GaugeConfigSection *upStream) { + size_t countGauges = gauges.size(); + for (size_t i = 0; i < countGauges; i++) { + if (gauges[i] == downStream) { + printf("%s is upstream(direct) of %s\n", upStream->GetName(), downStream->GetName()); + gaugeTree[i].push_back(upStream); + } + } + + for (size_t i = 0; i < countGauges; i++) { + std::vector<GaugeConfigSection *> *intGauges = &(gaugeTree[i]); + for (size_t j = 0; j < intGauges->size(); j++) { + if (intGauges->at(j) == downStream) { + printf("%s is upstream(indirect) of %s\n", upStream->GetName(), gauges[j]->GetName()); + intGauges->push_back(upStream); + } + } + } +} + +void GaugeMap::GaugeAverage(std::vector<GridNode> *nodes, std::vector<float> *currentValue, std::vector<float> *gaugeAvg) { + size_t countGauges = gauges.size(); + size_t countNodes = nodes->size(); + + // Zero out the partial vectors + for (size_t i = 0; i < countGauges; i++) { + partialVal[i] = 0; + partialArea[i] = 0; + } + + // Add up contributions to each gauge + for (size_t i = 0; i < countNodes; i++) { + GridNode *node = &((*nodes)[i]); + size_t gaugeIndex = gaugeMap[node->gauge]; + partialVal[gaugeIndex] += ((*currentValue)[i] * node->area); + partialArea[gaugeIndex] += node->area; + } + + for (size_t i = 0; i < countGauges; i++) { + float totalVal = 0; + float totalArea = 0; + + totalVal += partialVal[i]; + totalArea += partialArea[i]; + + std::vector<GaugeConfigSection *> *intGauges = &(gaugeTree[i]); + for (size_t j = 0; j < intGauges->size(); j++) { + size_t gaugeIndex = gaugeMap[intGauges->at(j)]; + totalVal += partialVal[gaugeIndex]; + totalArea += partialArea[gaugeIndex]; + } + + gaugeAvg->at(i) = (totalVal / totalArea); + } + +} + +void GaugeMap::GetGaugeArea(std::vector<GridNode> *nodes, std::vector<float> *gaugeArea) { + + size_t countGauges = gauges.size(); + size_t countNodes = nodes->size(); + + // Zero out the partial vectors + for (size_t i = 0; i < countGauges; i++) { + partialArea[i] = 0; + } + + // Add up contributions to each gauge + for (size_t i = 0; i < countNodes; i++) { + GridNode *node = &((*nodes)[i]); + size_t gaugeIndex = gaugeMap[node->gauge]; + partialArea[gaugeIndex] += node->area; + } + + for (size_t i = 0; i < countGauges; i++) { + float totalArea = 0; + + totalArea += partialArea[i]; + + std::vector<GaugeConfigSection *> *intGauges = &(gaugeTree[i]); + for (size_t j = 0; j < intGauges->size(); j++) { + size_t gaugeIndex = gaugeMap[intGauges->at(j)]; + totalArea += partialArea[gaugeIndex]; + } + + gaugeArea->at(i) = totalArea; + } + +} diff --git a/src/GaugeMap.h b/src/GaugeMap.h new file mode 100755 index 0000000..0e91f02 --- /dev/null +++ b/src/GaugeMap.h @@ -0,0 +1,22 @@ +#ifndef GAUGE_MAP_H +#define GAUGE_MAP_H + +#include <map> +#include <vector> +#include "GaugeConfigSection.h" +#include "GridNode.h" + +class GaugeMap { + public: + void Initialize(std::vector<GaugeConfigSection *> *newGauges); + void AddUpstreamGauge(GaugeConfigSection *downStream, GaugeConfigSection *upStream); + void GaugeAverage(std::vector<GridNode> *nodes, std::vector<float> *currentValue, std::vector<float> *gaugeAvg); + void GetGaugeArea(std::vector<GridNode> *nodes, std::vector<float> *gaugeArea); + private: + std::vector<GaugeConfigSection *> gauges; + std::vector<std::vector<GaugeConfigSection *> > gaugeTree; + std::map<GaugeConfigSection *, size_t> gaugeMap; + std::vector<float> partialVal, partialArea; +}; + +#endif diff --git a/src/GeographicProjection.cpp b/src/GeographicProjection.cpp new file mode 100755 index 0000000..7daa234 --- /dev/null +++ b/src/GeographicProjection.cpp @@ -0,0 +1,65 @@ +#include <cmath> +#include <cstdio> +#include "Defines.h" +#include "Messages.h" +#include "GeographicProjection.h" + +GeographicProjection::GeographicProjection() { + +} + +GeographicProjection::~GeographicProjection() { + +} + +float GeographicProjection::GetLen(float x, float y, FLOW_DIR dir) { + + switch (dir) { + case FLOW_NORTH: + case FLOW_SOUTH: + return metersSNPerCell; + case FLOW_EAST: + case FLOW_WEST: + return metersSNPerCell * cos(TORADIANS(y)); + case FLOW_NORTHEAST: + case FLOW_SOUTHEAST: + case FLOW_SOUTHWEST: + case FLOW_NORTHWEST: + return sqrt(pow(metersSNPerCell * cos(TORADIANS(y)), 2.0) + pow(metersSNPerCell, 2.0)); + default: + return 0; // We would do __builtin_unreachable(); but Apple's GCC lags behind + } + + return 0; + +} + +float GeographicProjection::GetArea(float x, float y) { + + float lenEW = metersSNPerCell * cos(TORADIANS(y)); + return (lenEW * metersSNPerCell) / 1000000; //We want km^2 + +} + +void GeographicProjection::ReprojectPoint(float lon, float lat, float *x, float *y) { + // Reproject a lat lon point into this projection + // Well we're already in geographic here... + + *x = lon; + *y = lat; +} + +void GeographicProjection::UnprojectPoint(float x, float y, float *lon, float *lat) { + // Project a lat lon to a lat lon + // Oh wait... already done! + + *lon = x; + *lat = y; +} + +void GeographicProjection::SetCellSize(float newCellSize) { + cellSize = newCellSize; + metersSNPerCell = cellSize * 110574; //110574m per degree of latitude! +} + + diff --git a/src/GeographicProjection.h b/src/GeographicProjection.h new file mode 100755 index 0000000..dce70c5 --- /dev/null +++ b/src/GeographicProjection.h @@ -0,0 +1,23 @@ +#ifndef GEOGRAPHIC_PROJECTION_H +#define GEOGRAPHIC_PROJECTION_H + +#include "Projection.h" + +class GeographicProjection : public Projection { + + public: + GeographicProjection(); + ~GeographicProjection(); + float GetLen(float x, float y, FLOW_DIR dir); + float GetArea(float x, float y); + void ReprojectPoint(float lon, float lat, float *x, float *y); + void UnprojectPoint(float x, float y, float *lon, float *lat); + void SetCellSize(float newCellSize); + + private: + float cellSize; + double metersSNPerCell; + +}; + +#endif diff --git a/src/Grid.h b/src/Grid.h new file mode 100755 index 0000000..3fb18ae --- /dev/null +++ b/src/Grid.h @@ -0,0 +1,114 @@ +#ifndef GRID_H +#define GRID_H + +#include <cstdio> +#include "BoundingBox.h" + +struct GridLoc { + long x; + long y; +}; + +struct RefLoc { + float x; + float y; +}; + +class Grid { + +public: + long numCols; + long numRows; + BoundingBox extent; + float cellSize; + + bool IsSpatialMatch(const Grid *testGrid) { + return ((numCols == testGrid->numCols) && (numRows == testGrid->numRows) + && (extent.left == testGrid->extent.left) && (extent.bottom == testGrid->extent.bottom) + && (cellSize == testGrid->cellSize)); + } + + bool GetGridLoc(float lon, float lat, GridLoc *pt) { + float xDiff = lon - extent.left; + float yDiff = extent.top - lat; + float xLoc = xDiff/cellSize; + float yLoc = yDiff/cellSize; + pt->x = (long)xLoc; + pt->y = (long)yLoc; + + if (pt->x < 0) { + pt->x = 0; + } else if (pt->x >= numCols) { + pt->x = numCols - 1; + } + + if (pt->y < 0) { + pt->y = 0; + } else if (pt->y >= numRows) { + pt->y = numRows - 1; + } + + if (extent.left > lon || extent.right < lon || extent.bottom > lat || extent.top < lat) { + return false; // This point isn't in the grid! + } else { + return true; + } + } + + bool GetRefLoc(long x, long y, RefLoc *pt) { + pt->x = (float)x * cellSize + extent.left; + pt->y = extent.top - (float)y * cellSize; + return true; + } + +}; + +class FloatGrid : public Grid { + +public: + FloatGrid() { + data = NULL; + backingStore = NULL; + } + ~FloatGrid() { + if (data) { + if (!backingStore) { + for (long i = 0; i < numRows; i++) { + if (data[i]) { + delete [] data[i]; + } + } + } else { + delete [] backingStore; + } + delete [] data; + } + } + float noData; + float **data; + float *backingStore; + +}; + +class LongGrid : public Grid { + +public: + LongGrid() { + data = NULL; + } + ~LongGrid() { + if (data) { + for (long i = 0; i < numRows; i++) { + if (data[i]) { + delete [] data[i]; + } + } + delete [] data; + } + } + long noData; + long **data; + +}; + +#endif diff --git a/src/GridNode.h b/src/GridNode.h new file mode 100755 index 0000000..ba592bb --- /dev/null +++ b/src/GridNode.h @@ -0,0 +1,30 @@ +#ifndef GRID_NODE_H +#define GRID_NODE_H + +#include <vector> +#include "GaugeConfigSection.h" + +#define INVALID_DOWNSTREAM_NODE -1ul + +struct BasicGridNode {}; + +struct GridNode { + long x; + long y; + RefLoc refLoc; + float slope; + long fac; + float area; + float contribArea; + float horLen; + bool channelGridCell; + GaugeConfigSection *gauge; + unsigned long downStreamNode; + unsigned long index; + unsigned long modelIndex; + BasicGridNode *modelNode; +}; + +typedef std::vector<GridNode> GridNodeVec; + +#endif diff --git a/src/GridWriter.cpp b/src/GridWriter.cpp new file mode 100755 index 0000000..37700f1 --- /dev/null +++ b/src/GridWriter.cpp @@ -0,0 +1,101 @@ +#include <climits> +#include "GridWriter.h" + +extern LongGrid *g_DEM; + +void GridWriter::Initialize(std::vector<GridNode> *nodes) { + maxX = 0; + minX = LONG_MAX; + maxY = 0; + minY = LONG_MAX; + + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + if (!node->gauge) { + continue; + } + if (node->x > maxX) { + maxX = node->x; + } + if (node->x < minX) { + minX = node->x; + } + if (node->y > maxY) { + maxY = node->y; + } + if (node->y < minY) { + minY = node->y; + } + } + + // We want to be inclusive + maxX++; + maxY++; + + long ncols = maxX - minX; + long nrows = maxY - minY; + + RefLoc ll, ur; + + // Initialize everything in the new grid + g_DEM->GetRefLoc(minX, maxY, &ll); + g_DEM->GetRefLoc(maxX, minY, &ur); + + grid.extent.left = ll.x; + grid.extent.bottom = ll.y; + grid.extent.right = ur.x; + grid.extent.top = ur.y; + grid.numCols = ncols; + grid.numRows = nrows; + grid.cellSize = g_DEM->cellSize; + grid.noData = -9999.0f; + + grid.data = new float*[grid.numRows]; + for (long i = 0; i < grid.numRows; i++) { + grid.data[i] = new float[grid.numCols]; + } + + //Grid is setup! Copy over no data values everywhere + for (long row = 0; row < nrows; row++) { + for (long col = 0; col < ncols; col++) { + grid.data[row][col] = grid.noData; + } + } +} + +void GridWriter::WriteGrid(std::vector<GridNode> *nodes, std::vector<float> *data, const char *file, bool ascii) { + + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &(nodes->at(i)); + if (!node->gauge) { + continue; + } + grid.data[node->y - minY][node->x - minX] = data->at(i); + } + + if (ascii) { + WriteFloatAscGrid(file, &grid); + } else { + WriteFloatTifGrid(file, &grid); + } +} + +void GridWriter::WriteGrid(std::vector<GridNode> *nodes, std::vector<double> *data, const char *file, bool ascii) { + + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &(nodes->at(i)); + if (!node->gauge) { + continue; + } + grid.data[node->y - minY][node->x - minX] = data->at(i); + } + + + if (ascii) { + WriteFloatAscGrid(file, &grid); + } else { + WriteFloatTifGrid(file, &grid); + } +} diff --git a/src/GridWriter.h b/src/GridWriter.h new file mode 100755 index 0000000..0a40e00 --- /dev/null +++ b/src/GridWriter.h @@ -0,0 +1,21 @@ +#ifndef GRIDWRITER_H +#define GRIDWRITER_H + +#include <vector> +#include "Grid.h" +#include "GridNode.h" +#include "AscGrid.h" +#include "TifGrid.h" + +class GridWriter { + public: + void Initialize(std::vector<GridNode> *nodes); + void WriteGrid(std::vector<GridNode> *nodes, std::vector<float> *data, const char *file, bool ascii = true); + void WriteGrid(std::vector<GridNode> *nodes, std::vector<double> *data, const char *file, bool ascii = true); + + private: + FloatGrid grid; + long minX, maxX, minY, maxY; +}; + +#endif diff --git a/src/GridWriterFull.cpp b/src/GridWriterFull.cpp new file mode 100755 index 0000000..cf8afec --- /dev/null +++ b/src/GridWriterFull.cpp @@ -0,0 +1,66 @@ +#include <climits> +#include "GridWriterFull.h" + +extern LongGrid *g_DEM; + +void GridWriterFull::Initialize() { + // Initialize everything in the new grid + + grid.extent.left = g_DEM->extent.left; + grid.extent.bottom = g_DEM->extent.bottom; + grid.extent.right = g_DEM->extent.right; + grid.extent.top = g_DEM->extent.top; + grid.numCols = g_DEM->numCols; + grid.numRows = g_DEM->numRows; + grid.cellSize = g_DEM->cellSize; + grid.noData = -9999.0f; + + grid.data = new float*[grid.numRows]; + for (long i = 0; i < grid.numRows; i++) { + grid.data[i] = new float[grid.numCols]; + } + + //Grid is setup! Copy over no data values everywhere + for (long row = 0; row < grid.numRows; row++) { + for (long col = 0; col < grid.numCols; col++) { + grid.data[row][col] = grid.noData; + } + } +} + +void GridWriterFull::WriteGrid(std::vector<GridNode> *nodes, std::vector<float> *data, const char *file, bool ascii) { + + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &(nodes->at(i)); + if (!node->gauge) { + continue; + } + grid.data[node->y][node->x] = data->at(i); + } + + if (ascii) { + WriteFloatAscGrid(file, &grid); + } else { + WriteFloatTifGrid(file, &grid); + } +} + +void GridWriterFull::WriteGrid(std::vector<GridNode> *nodes, std::vector<double> *data, const char *file, bool ascii) { + + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &(nodes->at(i)); + if (!node->gauge) { + continue; + } + grid.data[node->y][node->x] = data->at(i); + } + + + if (ascii) { + WriteFloatAscGrid(file, &grid); + } else { + WriteFloatTifGrid(file, &grid); + } +} diff --git a/src/GridWriterFull.h b/src/GridWriterFull.h new file mode 100755 index 0000000..d845024 --- /dev/null +++ b/src/GridWriterFull.h @@ -0,0 +1,20 @@ +#ifndef GRIDWRITER_H +#define GRIDWRITER_H + +#include <vector> +#include "Grid.h" +#include "GridNode.h" +#include "AscGrid.h" +#include "TifGrid.h" + +class GridWriterFull { + public: + void Initialize(); + void WriteGrid(std::vector<GridNode> *nodes, std::vector<float> *data, const char *file, bool ascii = true); + void WriteGrid(std::vector<GridNode> *nodes, std::vector<double> *data, const char *file, bool ascii = true); + + private: + FloatGrid grid; +}; + +#endif diff --git a/src/GriddedOutput.cpp b/src/GriddedOutput.cpp new file mode 100755 index 0000000..ee4aaeb --- /dev/null +++ b/src/GriddedOutput.cpp @@ -0,0 +1,48 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "GriddedOutput.h" + +const char *GriddedOutputText[] = { + "none", + "streamflow", + "soilmoisture", + "returnperiod", + "precip", + "pet", + "maxstreamflow", + "maxsoilmoisture", + "maxreturnperiod", + "snowwater", + "maxsnowwater", + "temperature", + "inundation", + "unitstreamflow", + "maxunitstreamflow", + "thresholdexceedance", + "maxthresholdexceedance", + "maxthresholdexceedancep", + "precipaccum", +}; + +const int GriddedOutputFlags[] = { + 0, + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + OG_DEPTH, + OG_UNITQ, + OG_MAXUNITQ, + OG_THRES, + OG_MAXTHRES, + OG_MAXTHRESP, + OG_PRECIPACCUM, +}; diff --git a/src/GriddedOutput.h b/src/GriddedOutput.h new file mode 100755 index 0000000..a3cb780 --- /dev/null +++ b/src/GriddedOutput.h @@ -0,0 +1,31 @@ +#ifndef GRIDDEDOUTPUT_H +#define GRIDDEDOUTPUT_H + +enum SUPPORTED_OUTPUT_GRIDS { + OG_NONE = 0, + OG_Q = 1, + OG_SM = 2, + OG_QRP = 4, + OG_PRECIP = 8, + OG_PET = 16, + OG_MAXQ = 32, + OG_MAXSM = 64, + OG_MAXQRP = 128, + OG_SWE = 256, + OG_MAXSWE = 512, + OG_TEMP = 1024, + OG_DEPTH = 2048, + OG_UNITQ = 4096, + OG_MAXUNITQ = 8192, + OG_THRES = 16384, + OG_MAXTHRES = 32768, + OG_MAXTHRESP = 65536, + OG_PRECIPACCUM = 131072, +}; + +#define OG_QTY 19 + +extern const char *GriddedOutputText[]; +extern const int GriddedOutputFlags[]; + +#endif diff --git a/src/HPModel.cpp b/src/HPModel.cpp new file mode 100755 index 0000000..8310df7 --- /dev/null +++ b/src/HPModel.cpp @@ -0,0 +1,117 @@ +#include <cstdio> +#include <cstring> +#include <cmath> +#include "DatedName.h" +#include "HPModel.h" + +HPModel::HPModel() { + +} + +HPModel::~HPModel() { + +} + +bool HPModel::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (hpNodes.size() != nodes->size()) { + hpNodes.resize(nodes->size()); + } + + // Fill in modelIndex in the gridNodes + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + node->modelIndex = i; + } + + InitializeParameters(paramSettings, paramGrids); + + return true; +} + +void HPModel::InitializeStates(TimeVar *beginTime, char *statePath) { + +} + +void HPModel::SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) { +} + +bool HPModel::WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture) { + + size_t numNodes = nodes->size(); + + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + HPGridNode *cNode = &(hpNodes[i]); + WaterBalanceInt(node, cNode, stepHours, precip->at(i), pet->at(i), &(fastFlow->at(i)), &(slowFlow->at(i))); + soilMoisture->at(i) = 100.0; + } + + return true; +} + +void HPModel::WaterBalanceInt(GridNode *node, HPGridNode *cNode, float stepHours, float precipIn, float petIn, float *fastFlow, float *slowFlow) { + float precip = precipIn * stepHours; // precipIn is mm/hr, precip is mm + float overland_precip = precip * cNode->params[PARAM_HP_SPLIT]; + float interflow_precip = precip * (1.0 - cNode->params[PARAM_HP_SPLIT]); + // Add Overland Excess Water to fastFlow + *fastFlow += (overland_precip / (stepHours * 3600.0f)); + + // Add Interflow Excess Water to slowFlow + *slowFlow += (interflow_precip / (stepHours * 3600.0f)); + +} + +void HPModel::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + size_t numNodes = nodes->size(); + size_t unused = 0; + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + HPGridNode *cNode = &(hpNodes[i]); + if (!node->gauge) { + unused++; + continue; + } + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_HP_QTY); + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_HP_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && g_DEM->IsSpatialMatch(grid)) { + if (grid->data[node->y][node->x] == 0) { + grid->data[node->y][node->x] = 0.01; + } + cNode->params[paramI] *= grid->data[node->y][node->x]; + } else if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] == 0) { + grid->data[pt.y][pt.x] = 0.01; + //printf("Using nodata value in param %s\n", modelParamStrings[MODEL_CREST][paramI]); + } + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + + if (cNode->params[PARAM_HP_PRECIP] < 0.0) { + printf("Node Precip Multiplier(%f) is less than 0, setting to 0.\n", cNode->params[PARAM_HP_PRECIP]); + cNode->params[PARAM_HP_PRECIP] = 0.0; + } else if (cNode->params[PARAM_HP_PRECIP] > 1.0) { + printf("Node Precip Multiplier(%f) is greater than 1, setting to 1.\n", cNode->params[PARAM_HP_PRECIP]); + cNode->params[PARAM_HP_PRECIP] = 1.0; + } + + if (cNode->params[PARAM_HP_SPLIT] < 0.0) { + printf("Node Precip Split (%f) is less than 0, setting to 0.\n", cNode->params[PARAM_HP_SPLIT]); + cNode->params[PARAM_HP_SPLIT] = 0.0; + } else if (cNode->params[PARAM_HP_SPLIT] > 1.0) { + printf("Node Precip Split (%f) is greater than 1, setting to 1.0.\n", cNode->params[PARAM_HP_SPLIT]); + cNode->params[PARAM_HP_SPLIT] = 1.0; + } + } + +} diff --git a/src/HPModel.h b/src/HPModel.h new file mode 100755 index 0000000..53f88e7 --- /dev/null +++ b/src/HPModel.h @@ -0,0 +1,31 @@ +#ifndef HP_MODEL_H +#define HP_MODEL_H + +#include "ModelBase.h" + +struct HPGridNode : BasicGridNode { + float params[PARAM_HP_QTY]; +}; + +class HPModel : public WaterBalanceModel { + + public: + HPModel(); + ~HPModel(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeStates(TimeVar *beginTime, char *statePath); + void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter); + bool WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture); + bool IsLumped() { return false; } + const char *GetName() { return "hp"; } + + private: + void WaterBalanceInt(GridNode *node, HPGridNode *cNode, float stepHours, float precipIn, float petIn, float *fastFlow, float *slowFlow); + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + + std::vector<GridNode> *nodes; + std::vector<HPGridNode> hpNodes; + +}; + +#endif diff --git a/src/HyMOD.cpp b/src/HyMOD.cpp new file mode 100755 index 0000000..d60bcb8 --- /dev/null +++ b/src/HyMOD.cpp @@ -0,0 +1,148 @@ +#include <algorithm> +#include <cmath> +#include <cstring> +#include <cstdio> +#include "HyMOD.h" + +HyMOD::HyMOD() { + +} + +HyMOD::~HyMOD() { + +} + +bool HyMOD::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (hymodNodes.size() != nodes->size()) { + hymodNodes.resize(nodes->size()); + } + + // Fill in modelNode in the gridNodes + std::vector<HyMODGridNode>::iterator citr = hymodNodes.begin(); + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + HyMODGridNode *cNode = &(*citr); + + node->modelNode = cNode; + + citr++; + } + + + InitializeParameters(paramSettings); + + return true; +} + +void HyMOD::InitializeStates(TimeVar *beginTime, char *statePath) { + +} + +void HyMOD::SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) { + +} + +bool HyMOD::WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture) { + + size_t numNodes = nodes->size(); + size_t i = 0; + + for (i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + HyMODGridNode *cNode = (HyMODGridNode*)node->modelNode; + WaterBalanceInt(node, cNode, stepHours, precip->at(i), pet->at(i)); + LocalRouteQF(node, cNode, stepHours); + LocalRouteSF(node, cNode, stepHours); + fastFlow->at(i) = cNode->dischargeQF; + slowFlow->at(i) = cNode->dischargeSF; + soilMoisture->at(i) = 0; + //discharge->at(i) = (cNode->dischargeQF + cNode->dischargeSF) * node->area * 0.277777777777778f / stepHours; // Convert from mm/time to cms + } + + return true; +} + +void HyMOD::WaterBalanceInt(GridNode *node, HyMODGridNode *cNode, float stepHours, float precipIn, float petIn) { + + float precip = precipIn * stepHours * cNode->params[PARAM_HYMOD_PRECIP]; // precipIn is mm/hr, precip is mm + float pet = petIn * stepHours; // petIn in mm/hr, pet is mm + + float Cbeg = cNode->CPar * (1 - pow(1 - (cNode->XHuz / cNode->params[PARAM_HYMOD_HUZ]), 1 + cNode->b)); // Contents at begining + float OV2 = std::max(0.0f, precip + cNode->XHuz - cNode->params[PARAM_HYMOD_HUZ]); // Compute OV2 if enough PP + float PPinf = precip - OV2; // PP that does not go to OV2 + float Hint = std::min(cNode->params[PARAM_HYMOD_HUZ], PPinf + cNode->XHuz); // Intermediate height + float Cint = cNode->CPar * (1 - pow(1 - Hint / cNode->params[PARAM_HYMOD_HUZ], 1 + cNode->b)); // Intermediate contents + float OV1 = std::max(0.0f, PPinf + Cbeg - Cint); // Compute OV1 + float OV = OV1 + OV2; // Compute total OV + float ET = std::min(pet, Cint); // Compute ET + float Cend = Cint - ET; // Final contents + float Hend = cNode->params[PARAM_HYMOD_HUZ] * ( 1 - pow(1 - Cend / cNode->CPar, 1 / (1 + cNode->b))); // Final height corresponding to SMA contents + + // Update states + cNode->XHuz = Hend; + cNode->XCuz = Cend; + + cNode->precipExcess = OV; +} + +void HyMOD::LocalRouteQF(GridNode *node, HyMODGridNode *cNode, float stepHours) { + float inFlow = cNode->params[PARAM_HYMOD_ALP] * cNode->precipExcess; + + float prevTransfer = inFlow; + + for (int i = 0; i < cNode->numQF; i++) { + float transfer = cNode->params[PARAM_HYMOD_KQ] * stepHours * cNode->Xq[i]; + cNode->Xq[i] = cNode->Xq[i] - transfer + prevTransfer; + prevTransfer = transfer; + } + + cNode->dischargeQF = prevTransfer; +} + +void HyMOD::LocalRouteSF(GridNode *node, HyMODGridNode *cNode, float stepHours) { + float inFlow = (1 - cNode->params[PARAM_HYMOD_ALP]) * cNode->precipExcess; + + float transfer = cNode->params[PARAM_HYMOD_KS] * stepHours * cNode->Xs; + cNode->Xs = cNode->Xs - transfer + inFlow; + + cNode->dischargeSF = transfer; +} + +void HyMOD::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings) { + + //This pass distributes parameters + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + HyMODGridNode *cNode = (HyMODGridNode*)node->modelNode; + + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_HYMOD_QTY); + + cNode->params[PARAM_HYMOD_KS] /= 24.0f; + cNode->params[PARAM_HYMOD_KQ] /= 24.0f; + + // Some of the parameters are special, deal with that here + cNode->b = log(1.0 - cNode->params[PARAM_HYMOD_B] / 2.0) / log(0.5); + cNode->CPar = cNode->params[PARAM_HYMOD_HUZ] / (1 + cNode->b); + cNode->numQF = (int)cNode->params[PARAM_HYMOD_NQ]; + + // States + cNode->XCuz = cNode->params[PARAM_HYMOD_XCUZ] * cNode->CPar; + cNode->XHuz = cNode->params[PARAM_HYMOD_HUZ] * (1 - pow((1 - cNode->XCuz / cNode->CPar), 1 / (1 + cNode->b))); + if (cNode->XHuz != cNode->XHuz) { + cNode->XHuz = 0; + } + cNode->Xs = cNode->params[PARAM_HYMOD_XS]; + if (cNode->Xq) { + delete [] cNode->Xq; + } + cNode->Xq = new float[cNode->numQF]; + for (int i = 0; i < cNode->numQF; i++) { + cNode->Xq[i] = cNode->params[PARAM_HYMOD_XQ]; + } + + } + +} diff --git a/src/HyMOD.h b/src/HyMOD.h new file mode 100755 index 0000000..5f1bcc4 --- /dev/null +++ b/src/HyMOD.h @@ -0,0 +1,47 @@ +#ifndef HYMOD_H +#define HYMOD_H + +#include "ModelBase.h" + +struct HyMODGridNode : BasicGridNode { + + HyMODGridNode() { Xq = NULL; } + + float params[PARAM_HYMOD_QTY]; + + // Params that aren't directly specified + double CPar, b; + int numQF; + + // States + float XCuz, XHuz, Xs; + float *Xq; + + // Local states + float precipExcess; + float dischargeQF, dischargeSF; +}; + +class HyMOD : public WaterBalanceModel { + + public: + HyMOD(); + ~HyMOD(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeStates(TimeVar *beginTime, char *statePath); + void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter); + bool WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture); + bool IsLumped() { return true; } + const char *GetName() { return "hymod"; } + + private: + void WaterBalanceInt(GridNode *node, HyMODGridNode *cNode, float stepHours, float precipIn, float petIn); + void LocalRouteQF(GridNode *node, HyMODGridNode *cNode, float stepHours); + void LocalRouteSF(GridNode *node, HyMODGridNode *cNode, float stepHours); + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings); + + std::vector<GridNode> *nodes; + std::vector<HyMODGridNode> hymodNodes; +}; + +#endif diff --git a/src/InundationCaliParamConfigSection.cpp b/src/InundationCaliParamConfigSection.cpp new file mode 100755 index 0000000..bae3983 --- /dev/null +++ b/src/InundationCaliParamConfigSection.cpp @@ -0,0 +1,113 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "InundationCaliParamConfigSection.h" + +std::map<std::string, InundationCaliParamConfigSection *> g_inundationCaliParamConfigs[INUNDATION_QTY]; + +InundationCaliParamConfigSection::InundationCaliParamConfigSection(char *nameVal, INUNDATIONS inundationVal) { + strcpy(name, nameVal); + gauge = NULL; + inundation = inundationVal; + int numParams = numInundationParams[inundation]; + modelParamMins = new float[numParams]; + modelParamMaxs = new float[numParams]; + modelParamInits = new float[numParams]; + paramsSet = new bool[numParams]; + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamInits, 0, sizeof(float)*numParams); + memset(paramsSet, 0, sizeof(bool)*numParams); + +} + +InundationCaliParamConfigSection::~InundationCaliParamConfigSection() { + delete [] modelParamMins; + delete [] modelParamMaxs; + delete [] modelParamInits; +} + +char *InundationCaliParamConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET InundationCaliParamConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numInundationParams[inundation]; + + if (!strcasecmp(name, "gauge")) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + gauge = itr->second; + } else { + + if (!gauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + + //Lets see if this belongs to a parameter + for (int i = 0; i < numParams; i++) { + if (strcasecmp(name, inundationParamStrings[inundation][i]) == 0) { + + if (paramsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + float minVal = 0, maxVal = 0, initVal = 0; + int count = sscanf(value, "%f,%f,%f", &minVal, &maxVal, &initVal); + + if (count < 2) { + ERROR_LOGF("Parameter \"%s\" has invalid calibration values!", name); + return INVALID_RESULT; + } + + modelParamMins[i] = minVal; + modelParamMaxs[i] = maxVal; + modelParamInits[i] = initVal; + paramsSet[i] = true; + + return VALID_RESULT; + } + } + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET InundationCaliParamConfigSection::ValidateSection() { + int numParams = numInundationParams[inundation]; + + if (!gauge) { + ERROR_LOG("The gauge on which calibration is to be performed was not set!"); + return INVALID_RESULT; + } + + for (int i = 0; i < numParams; i++) { + if (!paramsSet[i]) { + ERROR_LOGF("Incomplete inundation parameter set! Parameter \"%s\" was not given a value.", inundationParamStrings[inundation][i]); + return INVALID_RESULT; + } + } + + return VALID_RESULT; +} + +bool InundationCaliParamConfigSection::IsDuplicate(char *name, INUNDATIONS inundationVal) { + std::map<std::string, InundationCaliParamConfigSection *>::iterator itr = g_inundationCaliParamConfigs[inundationVal].find(name); + if (itr == g_inundationCaliParamConfigs[inundationVal].end()) { + return false; + } else { + return true; + } +} diff --git a/src/InundationCaliParamConfigSection.h b/src/InundationCaliParamConfigSection.h new file mode 100755 index 0000000..b74bac0 --- /dev/null +++ b/src/InundationCaliParamConfigSection.h @@ -0,0 +1,40 @@ +#ifndef CONFIG_INUNDATIONCALIPARAM_SECTION_H +#define CONFIG_INUNDATIONCALIPARAM_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" +#include "ObjectiveFunc.h" + +class InundationCaliParamConfigSection : public ConfigSection { + + public: + InundationCaliParamConfigSection(char *nameVal, INUNDATIONS routeVal); + ~InundationCaliParamConfigSection(); + + GaugeConfigSection *GetGauge() { return gauge; } + float *GetParamMins() { return modelParamMins; } + float *GetParamMaxs() { return modelParamMaxs; } + float *GetParamInits() { return modelParamInits; } + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name, INUNDATIONS inundationVal); + + private: + char name[CONFIG_MAX_LEN]; + INUNDATIONS inundation; + GaugeConfigSection *gauge; + float *modelParamMins; + float *modelParamMaxs; + float *modelParamInits; + bool *paramsSet; +}; + +extern std::map<std::string, InundationCaliParamConfigSection *> g_inundationCaliParamConfigs[]; + +#endif diff --git a/src/InundationParamSetConfigSection.cpp b/src/InundationParamSetConfigSection.cpp new file mode 100755 index 0000000..54d88db --- /dev/null +++ b/src/InundationParamSetConfigSection.cpp @@ -0,0 +1,135 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "InundationParamSetConfigSection.h" + +std::map<std::string, InundationParamSetConfigSection *> g_inundationParamSetConfigs[INUNDATION_QTY]; + +InundationParamSetConfigSection::InundationParamSetConfigSection(char *nameVal, INUNDATIONS inundationVal) { + strcpy(name, nameVal); + currentGauge = NULL; + currentParams = NULL; + currentParamsSet = NULL; + inundation = inundationVal; + paramGrids.resize(numInundationParams[inundation]); +} + +InundationParamSetConfigSection::~InundationParamSetConfigSection() { + +} + +char *InundationParamSetConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET InundationParamSetConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numInundationParams[inundation]; + + if (strcasecmp(name, "gauge") == 0) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", inundationParamStrings[inundation][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + if (IsDuplicateGauge(itr->second)) { + ERROR_LOGF("Duplicate gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + currentGauge = itr->second; + currentParams = new float[numParams]; + currentParamsSet = new bool[numParams]; + memset(currentParams, 0, sizeof(float)*numParams); + memset(currentParamsSet, 0, sizeof(bool)*numParams); + } else { + + // Lets see if this belongs to a parameter grid + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, inundationParamGridStrings[inundation][i]) == 0) { + paramGrids[i] = std::string(value); + return VALID_RESULT; + } + } + + if (!currentGauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + //Lets see if this belongs to a parameter scalar + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, inundationParamStrings[inundation][i]) == 0) { + + if (currentParamsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + currentParams[i] = atof(value); + currentParamsSet[i] = true; + + return VALID_RESULT; + } + } + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET InundationParamSetConfigSection::ValidateSection() { + int numParams = numInundationParams[inundation]; + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", inundationParamStrings[inundation][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + + + return VALID_RESULT; +} + +bool InundationParamSetConfigSection::IsDuplicate(char *name, INUNDATIONS inundationVal) { + std::map<std::string, InundationParamSetConfigSection *>::iterator itr = g_inundationParamSetConfigs[inundationVal].find(name); + if (itr == g_inundationParamSetConfigs[inundationVal].end()) { + return false; + } else { + return true; + } +} + +bool InundationParamSetConfigSection::IsDuplicateGauge(GaugeConfigSection *gaugeVal) { + std::map<GaugeConfigSection *, float *>::iterator itr = paramSettings.find(gaugeVal); + if (itr == paramSettings.end()) { + return false; + } else { + return true; + } +} diff --git a/src/InundationParamSetConfigSection.h b/src/InundationParamSetConfigSection.h new file mode 100755 index 0000000..9ea6cd8 --- /dev/null +++ b/src/InundationParamSetConfigSection.h @@ -0,0 +1,40 @@ +#ifndef CONFIG_INUNDATIONPARAMSET_SECTION_H +#define CONFIG_INUNDATIONPARAMSET_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" + +class InundationParamSetConfigSection : public ConfigSection { + + public: + InundationParamSetConfigSection(char *nameVal, INUNDATIONS inundationVal); + ~InundationParamSetConfigSection(); + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + std::map<GaugeConfigSection *, float *> *GetParamSettings() { return ¶mSettings; } + std::vector<std::string> *GetParamGrids() { return ¶mGrids; } + + static bool IsDuplicate(char *name, INUNDATIONS inundationVal); + + private: + bool IsDuplicateGauge(GaugeConfigSection *); + + char name[CONFIG_MAX_LEN]; + INUNDATIONS inundation; + GaugeConfigSection *currentGauge; + float *currentParams; + bool *currentParamsSet; + std::map<GaugeConfigSection *, float *> paramSettings; + std::vector<std::string> paramGrids; + + +}; + +extern std::map<std::string, InundationParamSetConfigSection *> g_inundationParamSetConfigs[]; + +#endif diff --git a/src/KWTest.cpp b/src/KWTest.cpp new file mode 100755 index 0000000..08f26d9 --- /dev/null +++ b/src/KWTest.cpp @@ -0,0 +1,121 @@ +#include <cstdio> + +#include "Defines.h" +#include "EF5.h" +#include "GridNode.h" +#include "GaugeConfigSection.h" +#include "Model.h" +#include "ModelBase.h" +#include "KinematicRoute.h" + +#define NUM_GRID_CELLS 101 +#define CELL_SIZE (200.0) +#define TOTAL_TIME_STEPS 1000 + +void PrintStartupMessage(); +void InitializeKW(); +void SimulateRouting(); + +std::vector<GridNode> nodes; +RoutingModel *rModel; +std::map<GaugeConfigSection *, float *> fullParamSettingsRoute; +std::vector<float> currentFF, currentSF, currentQ; +std::vector<FloatGrid *> paramGridsRoute; +GaugeConfigSection gaugeConfigSec("010000"); +float params[PARAM_KINEMATIC_QTY]; + +float inflowHydrograph[] = {0.0, 56.633694, 56.633694, 84.950541, 113.267388, 141.584235, 169.901082, 141.584235, 113.267388, 84.950541, 56.633694, 56.633694}; + +int main(int argc, char *argv[]) { + + PrintStartupMessage(); + InitializeKW(); + SimulateRouting(); + + return ERROR_SUCCESS; +} + +void InitializeKW() { + + rModel = new KWRoute(); + + nodes.resize(NUM_GRID_CELLS); + currentQ.resize(nodes.size()); + currentSF.resize(nodes.size()); + currentFF.resize(nodes.size()); + for (int currentNode = 0; currentNode < NUM_GRID_CELLS; currentNode++) { + GridNode *currentN = &(nodes)[currentNode]; + + //Setup the initial node for initiating the search for upstream nodes + currentN->index = currentNode; + currentN->x = currentNode; + currentN->y = 0; + if (currentNode == 0) { + currentN->downStreamNode = INVALID_DOWNSTREAM_NODE; + } else { + currentN->downStreamNode = currentNode-1; + } + currentN->horLen = CELL_SIZE; // meters + currentN->slope = 0.01; //10.0 / currentN->horLen; // We assume a difference in height of 1 meter because we know nothing else +currentN->area = (CELL_SIZE*CELL_SIZE) / 1000000.0; // km2 + currentN->fac = NUM_GRID_CELLS - currentNode + 1; + currentN->gauge = &gaugeConfigSec; + + currentQ[currentNode] = 0.0; + currentSF[currentNode] = 0.0; + currentFF[currentNode] = 0.0; + } + + // We only use lumped parameters here for ease of use. + for (size_t paramI = 0; paramI < PARAM_KINEMATIC_QTY; paramI++) { + paramGridsRoute.push_back(NULL); + } + + // Parameter setup + fullParamSettingsRoute[&gaugeConfigSec] = params; + params[PARAM_KINEMATIC_COEM] = 50.0; + params[PARAM_KINEMATIC_UNDER] = 0.1; + params[PARAM_KINEMATIC_LEAKI] = 1.0; + params[PARAM_KINEMATIC_TH] = -1.0; + params[PARAM_KINEMATIC_ISU] = 0.0; + params[PARAM_KINEMATIC_ALPHA] = 3.49; + params[PARAM_KINEMATIC_BETA] = 0.60; + + rModel->InitializeModel(&nodes, &fullParamSettingsRoute, ¶mGridsRoute); +} + +void SimulateRouting() { + FILE *file = fopen("results.csv", "w"); + fprintf(file, "%s", "Time,Inflow(m^3 s^-1),Outflow(m^3 s^-1)\n"); + float stepHoursReal = 5.0 / 60.0; /// 3600.0f; + + int numInflow = sizeof(inflowHydrograph)/sizeof(inflowHydrograph[0]); + float totalIn = 0.0, totalOut = 0.0; + for (int i = 0; i < TOTAL_TIME_STEPS; i++) { + float inflow = 0.0; + if (i < numInflow) { + inflow = inflowHydrograph[i]; + } + rModel->SetObsInflow(NUM_GRID_CELLS-1, inflow); + //currentFF[NUM_GRID_CELLS-1] = inflow * 3.6 / nodes[0].area; + + rModel->Route(stepHoursReal, ¤tFF, ¤tSF, ¤tQ); + totalIn += inflow; + totalOut += currentQ[0]; + printf("time %f, inflow %f, outlet %f\n", i * 12.0, inflow, currentQ[0]); + fprintf(file, "%f,%f,%f\n", i * 12.0, inflow, currentQ[0]); + + } + fclose(file); + printf("Total in %f, out %f\n", totalIn, totalOut); +} + +void PrintStartupMessage() { + printf("%s", "********************************************************\n"); + printf("%s", "** Ensemble Framework For Flash Flood Forecasting **\n"); + printf( "** Version %s **\n", EF5_VERSION); + printf("** KW Test **\n"); + printf("%s", "********************************************************\n"); + +} + diff --git a/src/KinematicRoute.cpp b/src/KinematicRoute.cpp new file mode 100755 index 0000000..ff5ebf9 --- /dev/null +++ b/src/KinematicRoute.cpp @@ -0,0 +1,494 @@ +#include <cstdio> +#include <cstring> +#include <cmath> +#include "DatedName.h" +#include "AscGrid.h" +#include "KinematicRoute.h" + +static const char *stateStrings[] = { + "pCQ", + "pOQ", + "IR", +}; + +KWRoute::KWRoute() { + +} + +KWRoute::~KWRoute() { + +} + +float KWRoute::SetObsInflow(long index, float inflow) { + KWGridNode *cNode = &(kwNodes[index]); + GridNode *node = &nodes->at(index); + float prev; + if (!node->channelGridCell) { + prev = cNode->states[STATE_KW_PQ] * node->horLen; + cNode->states[STATE_KW_PQ] = inflow / node->horLen; + cNode->incomingWaterOverland = inflow / node->horLen; + } else { + prev = cNode->states[STATE_KW_PQ]; + cNode->states[STATE_KW_PQ] = inflow; + cNode->incomingWaterChannel = inflow; + } + return prev; +} + +bool KWRoute::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (kwNodes.size() != nodes->size()) { + kwNodes.resize(nodes->size()); + } + + // Fill in modelIndex in the gridNodes + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + node->modelIndex = i; + KWGridNode *cNode = &(kwNodes[i]); + cNode->slopeSqrt = pow(node->slope, 0.5f); + cNode->hillSlopeSqrt = pow(node->slope*0.5, 0.5f); + cNode->incomingWater[KW_LAYER_INTERFLOW] = 0.0; + cNode->incomingWater[KW_LAYER_FASTFLOW] = 0.0; + cNode->incomingWaterOverland = 0.0; + cNode->incomingWaterChannel = 0.0; + for (int p = 0; p < STATE_KW_QTY; p++) { + cNode->states[p] = 0.0; + } + } + + InitializeParameters(paramSettings, paramGrids); + initialized = false; + maxSpeed = 1.0; + + return true; +} + +void KWRoute::InitializeStates(TimeVar *beginTime, char *statePath, std::vector<float> *fastFlow, std::vector<float> *slowFlow) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(beginTime->GetTM()); + + char buffer[255]; + for (int p = 0; p < STATE_KW_QTY; p++) { + sprintf(buffer, "%s/kwr_%s_%s.tif", statePath, stateStrings[p], timeStr.GetName()); + + FloatGrid *sGrid = ReadFloatTifGrid(buffer); + if (sGrid) { + printf("Using Kinematic Wave Routing %s State Grid %s\n", stateStrings[p], buffer); + if (true) {//g_DEM->IsSpatialMatch(sGrid)) { + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + KWGridNode *cNode = &(kwNodes[i]); + if (sGrid->data[node->y][node->x] != sGrid->noData) { + cNode->states[p] = sGrid->data[node->y][node->x]; + } + } + } else { + GridLoc pt; + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + KWGridNode *cNode = &(kwNodes[i]); + if (sGrid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && sGrid->data[pt.y][pt.x] != sGrid->noData) { + cNode->states[p] = sGrid->data[pt.y][pt.x]; + } + } + } + delete sGrid; + } else { + printf("Kinematic Wave Routing %s State Grid %s not found!\n", stateStrings[p], buffer); + } + } +} + +void KWRoute::SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(currentTime->GetTM()); + + std::vector<float> dataVals; + dataVals.resize(nodes->size()); + + char buffer[255]; + for (int p = 0; p < STATE_KW_QTY; p++) { + sprintf(buffer, "%s/kwr_%s_%s.tif", statePath, stateStrings[p], timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + KWGridNode *cNode = &(kwNodes[i]); + dataVals[i] = cNode->states[p]; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + } +} + +bool KWRoute::Route(float stepHours, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *discharge) { + + if (!initialized) { + initialized = true; + InitializeRouting(stepHours * 3600.0f); + } + + size_t numNodes = nodes->size(); + + for (long i = numNodes - 1; i >= 0; i--) { + KWGridNode *cNode = &(kwNodes[i]); + RouteInt(stepHours * 3600.0f, &(nodes->at(i)), cNode, fastFlow->at(i), slowFlow->at(i)); + } + + for (size_t i = 0; i < numNodes; i++) { + KWGridNode *cNode = &(kwNodes[i]); + slowFlow->at(i) = 0.0; //cNode->incomingWater[KW_LAYER_INTERFLOW]; + fastFlow->at(i) = 0.0;// cNode->incomingWater[KW_LAYER_FASTFLOW]; + cNode->incomingWaterOverland = 0.0; + cNode->incomingWaterChannel = 0.0; + if (!cNode->channelGridCell) { + float q = cNode->incomingWater[KW_LAYER_FASTFLOW] * nodes->at(i).horLen; + q += (cNode->incomingWater[KW_LAYER_INTERFLOW] * nodes->at(i).area / 3.6); + discharge->at(i) = q; // * (stepHours * 3600.0f); + } else { + discharge->at(i) = cNode->incomingWater[KW_LAYER_FASTFLOW]; + } + cNode->states[STATE_KW_IR] = cNode->states[STATE_KW_IR] + cNode->incomingWater[KW_LAYER_INTERFLOW]; + cNode->incomingWater[KW_LAYER_INTERFLOW] = 0.0; // Zero here so we can save states + cNode->incomingWater[KW_LAYER_FASTFLOW] = 0.0; // Zero here so we can save states + } + + //InitializeRouting(stepHours * 3600.0f); + + return true; +} + +void KWRoute::RouteInt(float stepSeconds, GridNode *node, KWGridNode *cNode, float fastFlow, float slowFlow ) { + + if (!cNode->channelGridCell) { + + float beta = 0.6; + float alpha = cNode->params[PARAM_KINEMATIC_ALPHA0]; + + + fastFlow /= 1000.0; //mm to m + float newInWater = fastFlow;// / node->horLen; + + float A, B, C, D, E; + float backDiffq = 0.0; + if (cNode->incomingWaterOverland + cNode->states[STATE_KW_PQ] > 0.0) { + backDiffq =pow((cNode->incomingWaterOverland + cNode->states[STATE_KW_PQ]) / 2.0, beta - 1.0); + if (!std::isfinite(backDiffq)) { + backDiffq = 0.0; + } + } + A = (stepSeconds / node->horLen) * cNode->incomingWaterOverland; + B = alpha * beta * cNode->states[STATE_KW_PQ] * backDiffq; + C = stepSeconds * newInWater; + D = stepSeconds / node->horLen; + E = alpha * beta * backDiffq; + float estq = (A + B + C)/(D + E); //cms/m + float rhs = A + alpha * pow(cNode->states[STATE_KW_PQ], beta) + stepSeconds * newInWater; + for (int itr = 0; itr < 10; itr++) { + float resError = (stepSeconds / node->horLen) * estq + alpha * pow(estq, beta) - rhs; + if (!std::isfinite(resError)) { + resError = 0.0; + } + if (fabsf(resError) < 0.01) { + break; + } + float resErrorD1 = (stepSeconds / node->horLen) + alpha * beta * pow(estq, beta - 1.0); + if (!std::isfinite(resErrorD1)) { + resErrorD1 = 1.0; + } + estq = estq - resError/resErrorD1; + if (estq < 0) { + estq = 0.0; + } + } + if (estq < 0.0) { + estq = 0.0; + } + + float newq = estq; + + cNode->states[STATE_KW_PQ] = newq; + if (node->downStreamNode != INVALID_DOWNSTREAM_NODE) { + kwNodes[nodes->at(node->downStreamNode).modelIndex].incomingWaterOverland += newq; + } + + + cNode->incomingWater[KW_LAYER_FASTFLOW] = newq; + + // Add Interflow Excess Water to Reservoir + cNode->states[STATE_KW_IR] += slowFlow; + double interflowLeak = cNode->states[STATE_KW_IR] * cNode->params[PARAM_KINEMATIC_LEAKI]; + //printf(" %f ", interflowLeak); + cNode->states[STATE_KW_IR] -= interflowLeak; + if (cNode->states[STATE_KW_IR] < 0) { + cNode->states[STATE_KW_IR] = 0; + } + + if (cNode->routeCNode[0][KW_LAYER_INTERFLOW]) { + double interflowLeak0 = interflowLeak * cNode->routeAmount[0][KW_LAYER_INTERFLOW] * node->area / cNode->routeNode[0][KW_LAYER_INTERFLOW]->area; + double leakAmount = interflowLeak0; + /*if (cNode->routeNode[0][KW_LAYER_INTERFLOW]->channelGridCell) { + printf(" 0 got %f ", cNode->routeCNode[0][KW_LAYER_INTERFLOW]->incomingWater[KW_LAYER_INTERFLOW]); + }*/ + cNode->routeCNode[0][KW_LAYER_INTERFLOW]->incomingWater[KW_LAYER_INTERFLOW] += leakAmount; + //*res += leakAmount; // Make this an atomic add for parallelization + } + + if (cNode->routeCNode[1][KW_LAYER_INTERFLOW]) { + double interflowLeak1 = interflowLeak * cNode->routeAmount[1][KW_LAYER_INTERFLOW] * node->area / cNode->routeNode[1][KW_LAYER_INTERFLOW]->area; + double leakAmount = interflowLeak1; + //printf(" 1 got %f ", leakAmount); + double *res = &(cNode->routeCNode[1][KW_LAYER_INTERFLOW]->incomingWater[KW_LAYER_INTERFLOW]); + *res += leakAmount; // Make this an atomic add for parallelization + } + + } else { + + // First do overland routing + + float beta = 0.6; + float alpha = cNode->params[PARAM_KINEMATIC_ALPHA0]; + slowFlow += cNode->incomingWater[KW_LAYER_INTERFLOW]; + //printf(" %f ", cNode->incomingWater[KW_LAYER_INTERFLOW]); + fastFlow /= 1000.0; //mm to m + slowFlow /= 1000.0; //mm to m + float newInWater = (fastFlow + slowFlow); + + float A, B, C, D, E; + float backDiffq = 0.0; + if (cNode->incomingWaterOverland + cNode->states[STATE_KW_PO] > 0.0) { + backDiffq =pow((cNode->incomingWaterOverland + cNode->states[STATE_KW_PO]) / 2.0, beta - 1.0); + if (!std::isfinite(backDiffq)) { + backDiffq = 0.0; + } + } + A = (stepSeconds / node->horLen) * cNode->incomingWaterOverland; + B = alpha * beta * cNode->states[STATE_KW_PO] * backDiffq; + C = stepSeconds * newInWater; + D = stepSeconds / node->horLen; + E = alpha * beta * backDiffq; + float estq = (A + B + C)/(D + E); //cms/m + float rhs = A + alpha * pow(cNode->states[STATE_KW_PO], beta) + stepSeconds * newInWater; + for (int itr = 0; itr < 10; itr++) { + float resError = (stepSeconds / node->horLen) * estq + alpha * pow(estq, beta) - rhs; + if (!std::isfinite(resError)) { + resError = 0.0; + } + if (fabsf(resError) < 0.01) { + break; + } + float resErrorD1 = (stepSeconds / node->horLen) + alpha * beta * pow(estq, beta - 1.0); + if (!std::isfinite(resErrorD1)) { + resErrorD1 = 1.0; + } + estq = estq - resError/resErrorD1; + if (estq < 0) { + estq = 0.0; + } + } + if (estq < 0) { + estq = 0.0; + } + float newq = estq; + + cNode->states[STATE_KW_PO] = newq; + + + + // Here we compute channel routing + beta = cNode->params[PARAM_KINEMATIC_BETA]; + alpha = cNode->params[PARAM_KINEMATIC_ALPHA]; + + //Channel Flow + //Compute Q at current grid point + float backDiffQ = 0.0; + if (cNode->incomingWaterChannel + cNode->states[STATE_KW_PQ] > 0.0) { + backDiffQ =pow((cNode->incomingWaterChannel + cNode->states[STATE_KW_PQ]) / 2.0, beta - 1.0); + if (!std::isfinite(backDiffQ)) { + backDiffQ = 0.0; + } + } + + A = (stepSeconds / node->horLen) * cNode->incomingWaterChannel; + B = alpha * beta * cNode->states[STATE_KW_PQ] * backDiffQ; + C = stepSeconds * newq; + D = stepSeconds / node->horLen; + E = alpha * beta * backDiffQ; + float estQ = (A + B + C)/(D + E); //cms + rhs = A + alpha * pow(cNode->states[STATE_KW_PQ], beta) + stepSeconds * newq; + for (int itr = 0; itr < 10; itr++) { + float resError = (stepSeconds / node->horLen) * estQ + alpha * pow(estQ, beta) - rhs; + if (!std::isfinite(resError)) { + resError = 0.0; + } + if (fabsf(resError) < 0.01) { + break; + } + float resErrorD1 = (stepSeconds / node->horLen) + alpha * beta * pow(estQ, beta - 1.0); + if (!std::isfinite(resErrorD1)) { + resErrorD1 = 1.0; + } + estQ = estQ - resError/resErrorD1; + if (estQ < 0) { + estQ = 0.0; + } + } + if (estQ < 0) { + estQ = 0.0; + } + float newWater = estQ; + /*if (newWater != newWater) { + printf("New water is %f (%f, %f) %f %f [%f %f %f %f %f] %f %f\n", newWater, cNode->incomingWaterChannel, cNode->states[STATE_KW_PQ], newq, cNode->incomingWaterOverland, A, B, C, D, E, alpha, 0.0); + }*/ + cNode->states[STATE_KW_PQ] = newWater; //Update previous Q for further routing if "steps" > 1 + if (node->downStreamNode != INVALID_DOWNSTREAM_NODE) { + kwNodes[nodes->at(node->downStreamNode).modelIndex].incomingWaterChannel += newWater; + } + + cNode->incomingWater[KW_LAYER_FASTFLOW] = newWater; + cNode->incomingWater[KW_LAYER_INTERFLOW] = 0.0; + } + +} + +void KWRoute::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + size_t numNodes = nodes->size(); + size_t unused = 0; + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + KWGridNode *cNode = &(kwNodes[i]); + if (!node->gauge) { + unused++; + continue; + } + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_KINEMATIC_QTY); + + if (!paramGrids->at(PARAM_KINEMATIC_ISU)) { + cNode->states[STATE_KW_IR] = cNode->params[PARAM_KINEMATIC_ISU]; + } + cNode->incomingWater[KW_LAYER_INTERFLOW] = 0.0; + cNode->incomingWater[KW_LAYER_FASTFLOW] = 0.0; + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_KINEMATIC_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && g_DEM->IsSpatialMatch(grid)) { + if (grid->data[node->y][node->x] == 0) { + grid->data[node->y][node->x] = 0.01; + } + cNode->params[paramI] *= grid->data[node->y][node->x]; + } else if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] == 0) { + grid->data[pt.y][pt.x] = 0.01; + //printf("Using nodata value in param %s\n", modelParamStrings[MODEL_CREST][paramI]); + } + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + + if (cNode->params[PARAM_KINEMATIC_LEAKI] < 0.0) { + //printf("Node Leak Interflow(%f) is less than 0, setting to 0.\n", cNode->params[PARAM_KINEMATIC_LEAKI]); + cNode->params[PARAM_KINEMATIC_LEAKI] = 0.0; + } else if (cNode->params[PARAM_KINEMATIC_LEAKI] > 1.0) { + //printf("Node Leak Interflow(%f) is greater than 1, setting to 1.\n", cNode->params[PARAM_KINEMATIC_LEAKI]); + cNode->params[PARAM_KINEMATIC_LEAKI] = 1.0; + } + + if (cNode->params[PARAM_KINEMATIC_ALPHA] < 0.0) { + //printf("Node Alpha(%f) is less than 0, setting to 1.\n", cNode->params[PARAM_KINEMATIC_ALPHA]); + cNode->params[PARAM_KINEMATIC_ALPHA] = 1.0; + } + + if (cNode->params[PARAM_KINEMATIC_ALPHA0] < 0.0) { + //printf("Node Alpha0(%f) is less than 0, setting to 1.\n", cNode->params[PARAM_KINEMATIC_ALPHA0]); + cNode->params[PARAM_KINEMATIC_ALPHA0] = 1.0; + } + + if (cNode->params[PARAM_KINEMATIC_BETA] < 0.0) { + //printf("Node Beta(%f) is less than 0, setting to 0.6.\n", cNode->params[PARAM_KINEMATIC_BETA]); + cNode->params[PARAM_KINEMATIC_BETA] = 0.6; + } + + + + if (node->fac > cNode->params[PARAM_KINEMATIC_TH]) { + node->channelGridCell = true; + cNode->channelGridCell = true; + } else { + node->channelGridCell = false; + cNode->channelGridCell = false; + } + + } + +} + +void KWRoute::InitializeRouting(float timeSeconds) { + + //This pass distributes parameters & calculates the time it takes for water to cross the grid cell. + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + KWGridNode *cNode = &(kwNodes[i]); + + // Calculate the water speed for interflow + float speedUnder = cNode->params[PARAM_KINEMATIC_UNDER] * cNode->slopeSqrt; + + float nexTimeUnder = node->horLen / speedUnder; + cNode->nexTime[KW_LAYER_INTERFLOW] = nexTimeUnder; + + } + + //This pass figures out which cell water is routed to + for (size_t i = 0; i < numNodes; i++) { + GridNode *currentNode, *previousNode; + float currentSeconds, previousSeconds; + GridNode *node = &nodes->at(i); + KWGridNode *cNode = &(kwNodes[i]); + + // Interflow routing + previousSeconds = 0; + currentSeconds = 0; + currentNode = node; + previousNode = NULL; + while (currentSeconds < timeSeconds && currentNode && !kwNodes[currentNode->modelIndex].channelGridCell) { + if (currentNode) { + previousSeconds = currentSeconds; + previousNode = currentNode; + currentSeconds += kwNodes[currentNode->modelIndex].nexTime[KW_LAYER_INTERFLOW]; + if (currentNode->downStreamNode != INVALID_DOWNSTREAM_NODE) { + currentNode = &(nodes->at(currentNode->downStreamNode)); + } else { + currentNode = NULL; + } + } else { + if (timeSeconds > currentSeconds) { + previousNode = NULL; + } + break; // We have effectively run out of nodes to transverse, this is done! + } + } + + cNode->routeNode[0][KW_LAYER_INTERFLOW] = currentNode; + cNode->routeCNode[0][KW_LAYER_INTERFLOW] = (currentNode) ? &(kwNodes[currentNode->modelIndex]) : NULL; + cNode->routeNode[1][KW_LAYER_INTERFLOW] = previousNode; + cNode->routeCNode[1][KW_LAYER_INTERFLOW] = (previousNode) ? &(kwNodes[previousNode->modelIndex]) : NULL; + if (currentNode && !kwNodes[currentNode->modelIndex].channelGridCell) { + if ((currentSeconds - previousSeconds) > 0) { + cNode->routeAmount[0][KW_LAYER_INTERFLOW] = (timeSeconds - previousSeconds) / (currentSeconds - previousSeconds); + cNode->routeAmount[1][KW_LAYER_INTERFLOW] = 1.0 - cNode->routeAmount[0][KW_LAYER_INTERFLOW]; + } + } else { + cNode->routeAmount[0][KW_LAYER_INTERFLOW] = 1.0; + cNode->routeAmount[1][KW_LAYER_INTERFLOW] = 0.0; + } + } +} + diff --git a/src/KinematicRoute.h b/src/KinematicRoute.h new file mode 100755 index 0000000..c60746a --- /dev/null +++ b/src/KinematicRoute.h @@ -0,0 +1,62 @@ +#ifndef KW_MODEL_H +#define KW_MODEL_H + +#include "ModelBase.h" + +enum KW_LAYER { + KW_LAYER_FASTFLOW, + KW_LAYER_INTERFLOW, + KW_LAYER_QTY, +}; + +enum STATES_KW { + STATE_KW_PQ, + STATE_KW_PO, + STATE_KW_IR, + STATE_KW_QTY +}; + +struct KWGridNode : BasicGridNode { + float params[PARAM_KINEMATIC_QTY]; + float states[STATE_KW_QTY]; + + bool channelGridCell; + double slopeSqrt; + double hillSlopeSqrt; + + double nexTime[KW_LAYER_QTY]; // This is a by product of computing cell routing + KWGridNode *routeCNode[2][KW_LAYER_QTY]; // This is the node we route water to + GridNode *routeNode[2][KW_LAYER_QTY]; + double routeAmount[2][KW_LAYER_QTY]; + double incomingWater[KW_LAYER_QTY]; + + //double reservoirs[KW_LAYER_QTY]; // CREST has two excess storage reservoirs (overland & interflow) + + //double previousStreamflow; //cms + //double previousOverland; + double incomingWaterOverland, incomingWaterChannel; +}; + +class KWRoute : public RoutingModel { + +public: + KWRoute(); + ~KWRoute(); + float SetObsInflow(long index, float inflow); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeStates(TimeVar *beginTime, char *statePath, std::vector<float> *fastFlow, std::vector<float> *slowFlow); + void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter); + bool Route(float stepHours, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *discharge); + float GetMaxSpeed() { return maxSpeed; } +private: + void RouteInt(float stepSeconds, GridNode *node, KWGridNode *cNode, float fastFlow, float slowFlow); + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeRouting(float timeSeconds); + + std::vector<GridNode> *nodes; + std::vector<KWGridNode> kwNodes; + float maxSpeed; + bool initialized; +}; + +#endif diff --git a/src/LAEAProjection.cpp b/src/LAEAProjection.cpp new file mode 100755 index 0000000..d05e1db --- /dev/null +++ b/src/LAEAProjection.cpp @@ -0,0 +1,84 @@ +#include <cmath> +#include <cstdio> +#include "Defines.h" +#include "Messages.h" +#include "LAEAProjection.h" + +LAEAProjection::LAEAProjection() { + stan_par = TORADIANS(45.0); + cent_lon = TORADIANS(-100.0); + a = 6370997.0; +} + +LAEAProjection::~LAEAProjection() { + +} + +float LAEAProjection::GetLen(float x, float y, FLOW_DIR dir) { + + switch (dir) { + case FLOW_NORTH: + case FLOW_SOUTH: + case FLOW_EAST: + case FLOW_WEST: + return metersSNPerCell; + case FLOW_NORTHEAST: + case FLOW_SOUTHEAST: + case FLOW_SOUTHWEST: + case FLOW_NORTHWEST: + return metersDiagPerCell; + default: + return 0; // We would do __builtin_unreachable(); but Apple's GCC lags behind + } + + return 0; + +} + +float LAEAProjection::GetArea(float x, float y) { + + return area; + +} + +void LAEAProjection::ReprojectPoint(float lon, float lat, float *x, float *y) { + // Reproject a geographic point into a LAEA point... + + lon = TORADIANS(lon); + lat = TORADIANS(lat); + + // Equations from mathworld.wolfram.com + float kPrime = sqrt(2.0 / (1.0 + sin(stan_par) * sin(lat) + cos(stan_par) * cos(lat) * cos(lon - cent_lon))); + float projX = kPrime * cos(lat) * sin(lon - cent_lon); + float projY = kPrime * (cos(stan_par) * sin(lat) - sin(stan_par) * cos(lat) * cos(lon - cent_lon)); + + *x = a*projX; + *y = a*projY; + +} + +void LAEAProjection::UnprojectPoint(float x, float y, float *lon, float *lat) { + // Project a LAEA point into geographic! + // Equations from mathworld.wolfram.com + + float projX = x / a; + float projY = y / a; + + float rho = sqrt(pow(projX, 2) + pow(projY, 2)); + float c = 2 * asin(0.5 * rho); + float geoLat = asin(cos(c) * sin(stan_par) + (projY * sin(c) * cos(stan_par)) / rho); + float geoLon = cent_lon + atan( (projX * sin(c)) / ( rho * cos(stan_par) * cos(c) - projY * sin(stan_par) * sin(c)) ); + + *lon = TODEGREES(geoLon); + *lat = TODEGREES(geoLat); + +} + +void LAEAProjection::SetCellSize(float newCellSize) { + cellSize = newCellSize; + metersSNPerCell = cellSize; + metersDiagPerCell = sqrt(pow(cellSize, 2) + pow(cellSize, 2)); + area = pow(cellSize, 2) / 1000000; // Want km^2 +} + + diff --git a/src/LAEAProjection.h b/src/LAEAProjection.h new file mode 100755 index 0000000..22d7c2d --- /dev/null +++ b/src/LAEAProjection.h @@ -0,0 +1,25 @@ +#ifndef LAEA_PROJECTION_H +#define LAEA_PROJECTION_H + +#include "Projection.h" + +class LAEAProjection : public Projection { + + public: + LAEAProjection(); + ~LAEAProjection(); + float GetLen(float x, float y, FLOW_DIR dir); + float GetArea(float x, float y); + void ReprojectPoint(float lon, float lat, float *x, float *y); + void UnprojectPoint(float x, float y, float *lon, float *lat); + void SetCellSize(float newCellSize); + + private: + float cellSize; + float area; + float metersSNPerCell; + float metersDiagPerCell; + float stan_par, cent_lon, a; +}; + +#endif diff --git a/src/LinearRoute.cpp b/src/LinearRoute.cpp new file mode 100755 index 0000000..c715dc5 --- /dev/null +++ b/src/LinearRoute.cpp @@ -0,0 +1,315 @@ +#include <cstdio> +#include <cstring> +#include <cmath> +#include "DatedName.h" +#include "AscGrid.h" +#include "LinearRoute.h" + +LRRoute::LRRoute() { + +} + +LRRoute::~LRRoute() { + +} + +float LRRoute::SetObsInflow(long index, float inflow) { + return 0.0; +} + +bool LRRoute::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (lrNodes.size() != nodes->size()) { + lrNodes.resize(nodes->size()); + } + + // Fill in modelIndex in the gridNodes + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + node->modelIndex = i; + LRGridNode *cNode = &(lrNodes[i]); + cNode->slopeSqrt = pow(node->slope, 0.5f); + } + + InitializeParameters(paramSettings, paramGrids); + initialized = false; + maxSpeed = 1.0; + + return true; +} + +void LRRoute::InitializeStates(TimeVar *beginTime, char *statePath, std::vector<float> *fastFlow, std::vector<float> *slowFlow) { + +} +void LRRoute::SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) { + +} + +bool LRRoute::Route(float stepHours, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *discharge) { + + if (!initialized) { + initialized = true; + InitializeRouting(stepHours * 3600.0f); + } + + size_t numNodes = nodes->size(); + + for (size_t i = 0; i < numNodes; i++) { + LRGridNode *cNode = &(lrNodes[i]); + RouteInt(&(nodes->at(i)), cNode, fastFlow->at(i), slowFlow->at(i)); + } + + for (size_t i = 0; i < numNodes; i++) { + LRGridNode *cNode = &(lrNodes[i]); + fastFlow->at(i) = cNode->incomingWater[LR_LAYER_OVERLAND]; + cNode->incomingWater[LR_LAYER_OVERLAND] = 0.0; + slowFlow->at(i) = cNode->incomingWater[LR_LAYER_INTERFLOW]; + cNode->incomingWater[LR_LAYER_INTERFLOW] = 0.0; + + } + + InitializeRouting(stepHours * 3600.0f); + + return true; +} + +void LRRoute::RouteInt(GridNode *node, LRGridNode *cNode, float fastFlow, float slowFlow) { + + if (!node->channelGridCell) { + cNode->reservoirs[LR_LAYER_OVERLAND] += fastFlow; + } + + double overlandLeak = cNode->reservoirs[LR_LAYER_OVERLAND] * cNode->params[PARAM_LINEAR_LEAKO]; + cNode->reservoirs[LR_LAYER_OVERLAND] -= overlandLeak; + if (cNode->reservoirs[LR_LAYER_OVERLAND] < 0) { + cNode->reservoirs[LR_LAYER_OVERLAND] = 0; + } + + if (node->channelGridCell) { + overlandLeak += fastFlow; + } + + // Add Interflow Excess Water to Reservoir + cNode->reservoirs[LR_LAYER_INTERFLOW] += slowFlow; + double interflowLeak = cNode->reservoirs[LR_LAYER_INTERFLOW] * cNode->params[PARAM_LINEAR_LEAKI]; + cNode->reservoirs[LR_LAYER_INTERFLOW] -= interflowLeak; + if (cNode->reservoirs[LR_LAYER_INTERFLOW] < 0) { + cNode->reservoirs[LR_LAYER_INTERFLOW] = 0; + } + + if (cNode->routeCNode[0][LR_LAYER_OVERLAND]) { + double overlandLeak0 = overlandLeak * cNode->routeAmount[0][LR_LAYER_OVERLAND] * node->area / cNode->routeNode[0][LR_LAYER_OVERLAND]->area; + double leakAmount = overlandLeak0; + double *res = &(cNode->routeCNode[0][LR_LAYER_OVERLAND]->incomingWater[LR_LAYER_OVERLAND]); + *res += leakAmount; // Make this an atomic add for parallelization + } + + if (cNode->routeCNode[1][LR_LAYER_OVERLAND]) { + double overlandLeak1 = overlandLeak * cNode->routeAmount[1][LR_LAYER_OVERLAND] * node->area / cNode->routeNode[1][LR_LAYER_OVERLAND]->area; + double leakAmount = overlandLeak1; + double *res = &(cNode->routeCNode[1][LR_LAYER_OVERLAND]->incomingWater[LR_LAYER_OVERLAND]); + *res += leakAmount; // Make this an atomic add for parallelization + } + + if (cNode->routeCNode[0][LR_LAYER_INTERFLOW]) { + double interflowLeak0 = interflowLeak * cNode->routeAmount[0][LR_LAYER_INTERFLOW] * node->area / cNode->routeNode[0][LR_LAYER_INTERFLOW]->area; + double leakAmount = interflowLeak0; + double *res = &(cNode->routeCNode[0][LR_LAYER_INTERFLOW]->incomingWater[LR_LAYER_INTERFLOW]); + *res += leakAmount; // Make this an atomic add for parallelization + } + + if (cNode->routeCNode[1][LR_LAYER_INTERFLOW]) { + double interflowLeak1 = interflowLeak * cNode->routeAmount[1][LR_LAYER_INTERFLOW] * node->area / cNode->routeNode[1][LR_LAYER_INTERFLOW]->area; + double leakAmount = interflowLeak1; + double *res = &(cNode->routeCNode[1][LR_LAYER_INTERFLOW]->incomingWater[LR_LAYER_INTERFLOW]); + *res += leakAmount; // Make this an atomic add for parallelization + } + +} + +void LRRoute::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + size_t numNodes = nodes->size(); + size_t unused = 0; + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + LRGridNode *cNode = &(lrNodes[i]); + if (!node->gauge) { + unused++; + continue; + } + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_LINEAR_QTY); + + if (!paramGrids->at(PARAM_LINEAR_ISO)) { + cNode->reservoirs[LR_LAYER_OVERLAND] = cNode->params[PARAM_LINEAR_ISO]; + } + if (!paramGrids->at(PARAM_LINEAR_ISU)) { + cNode->reservoirs[LR_LAYER_INTERFLOW] = cNode->params[PARAM_LINEAR_ISU]; + } + cNode->incomingWater[LR_LAYER_OVERLAND] = 0.0; + cNode->incomingWater[LR_LAYER_INTERFLOW] = 0.0; + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_LINEAR_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && g_DEM->IsSpatialMatch(grid)) { + if (grid->data[node->y][node->x] == 0) { + grid->data[node->y][node->x] = 0.01; + } + cNode->params[paramI] *= grid->data[node->y][node->x]; + } else if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] == 0) { + grid->data[pt.y][pt.x] = 0.01; + //printf("Using nodata value in param %s\n", modelParamStrings[MODEL_CREST][paramI]); + } + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + + if (cNode->params[PARAM_LINEAR_LEAKO] < 0.0) { + printf("Node Leak Overland(%f) is less than 0, setting to 0.\n", cNode->params[PARAM_LINEAR_LEAKO]); + cNode->params[PARAM_LINEAR_LEAKO] = 0.0; + } else if (cNode->params[PARAM_LINEAR_LEAKO] > 1.0) { + printf("Node Leak Overland(%f) is greater than 1, setting to 1.\n", cNode->params[PARAM_LINEAR_LEAKO]); + cNode->params[PARAM_LINEAR_LEAKO] = 1.0; + } + + if (cNode->params[PARAM_LINEAR_LEAKI] < 0.0) { + printf("Node Leak Interflow(%f) is less than 0, setting to 0.\n", cNode->params[PARAM_LINEAR_LEAKI]); + cNode->params[PARAM_LINEAR_LEAKI] = 0.0; + } else if (cNode->params[PARAM_LINEAR_LEAKI] > 1.0) { + printf("Node Leak Interflow(%f) is greater than 1, setting to 1.\n", cNode->params[PARAM_LINEAR_LEAKI]); + cNode->params[PARAM_LINEAR_LEAKI] = 1.0; + } + + if (node->fac > cNode->params[PARAM_LINEAR_TH]) { + node->channelGridCell = true; + } else { + node->channelGridCell = false; + } + + } + +} + +void LRRoute::InitializeRouting(float timeSeconds) { + + maxSpeed = 0; + + //This pass distributes parameters & calculates the time it takes for water to cross the grid cell. + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + LRGridNode *cNode = &(lrNodes[i]); + + float waterDepth = (cNode->reservoirs[LR_LAYER_OVERLAND] * cNode->params[PARAM_LINEAR_LEAKO] + cNode->reservoirs[LR_LAYER_INTERFLOW] * cNode->params[PARAM_LINEAR_LEAKI]) / 1000.0f; + if (node->channelGridCell) { + waterDepth += (cNode->incomingWater[LR_LAYER_OVERLAND]) / 1000.0f; + } + if (waterDepth < 0.0001) { + waterDepth = 0.0001; + } + + // Calculate the approximate speed of the water in meters per second (thus COEM is in meters per second) + // Slope is meters vertical change over meters horizontal change so thus unitless + float speed = pow(waterDepth, 0.66) * cNode->slopeSqrt; + + // We have different mannings roughness multipliers for overland & channel grid cells + if (node->fac > cNode->params[PARAM_LINEAR_TH]) { + speed *= cNode->params[PARAM_LINEAR_RIVER]; + } else { + speed *= cNode->params[PARAM_LINEAR_COEM]; + } + + if (speed > maxSpeed) { + maxSpeed = speed; + } + + // Calculate the water speed for interflow + float speedUnder = cNode->params[PARAM_LINEAR_UNDER] * cNode->slopeSqrt; + + float nexTime = node->horLen / speed; + float nexTimeUnder = node->horLen / speedUnder; + cNode->nexTime[LR_LAYER_OVERLAND] = nexTime; + cNode->nexTime[LR_LAYER_INTERFLOW] = nexTimeUnder; + + } + + //This pass figures out which cell water is routed to + for (size_t i = 0; i < numNodes; i++) { + GridNode *currentNode, *previousNode; + float currentSeconds, previousSeconds; + GridNode *node = &nodes->at(i); + LRGridNode *cNode = &(lrNodes[i]); + + // Overland routing + previousSeconds = 0; + currentSeconds = 0; + currentNode = node; + previousNode = NULL; + while (currentSeconds < timeSeconds) { + if (currentNode) { + previousSeconds = currentSeconds; + previousNode = currentNode; + currentSeconds += lrNodes[currentNode->modelIndex].nexTime[LR_LAYER_OVERLAND]; + if (currentNode->downStreamNode != INVALID_DOWNSTREAM_NODE) { + currentNode = &(nodes->at(currentNode->downStreamNode)); + } else { + currentNode = NULL; + } + } else { + if (timeSeconds > currentSeconds) { + previousNode = NULL; + } + break; // We have effectively run out of nodes to transverse, this is done! + } + } + + cNode->routeNode[0][LR_LAYER_OVERLAND] = currentNode; + cNode->routeCNode[0][LR_LAYER_OVERLAND] = (currentNode) ? &(lrNodes[currentNode->modelIndex]) : NULL; + cNode->routeNode[1][LR_LAYER_OVERLAND] = previousNode; + cNode->routeCNode[1][LR_LAYER_OVERLAND] = (previousNode) ? &(lrNodes[previousNode->modelIndex]) : NULL; + if ((currentSeconds - previousSeconds) > 0) { + cNode->routeAmount[0][LR_LAYER_OVERLAND] = (timeSeconds - previousSeconds) / (currentSeconds - previousSeconds); + cNode->routeAmount[1][LR_LAYER_OVERLAND] = 1.0 - cNode->routeAmount[0][LR_LAYER_OVERLAND]; + } + + // Interflow routing + previousSeconds = 0; + currentSeconds = 0; + currentNode = node; + previousNode = NULL; + while (currentSeconds < timeSeconds) { + if (currentNode) { + previousSeconds = currentSeconds; + previousNode = currentNode; + currentSeconds += lrNodes[currentNode->modelIndex].nexTime[LR_LAYER_INTERFLOW]; + if (currentNode->downStreamNode != INVALID_DOWNSTREAM_NODE) { + currentNode = &(nodes->at(currentNode->downStreamNode)); + } else { + currentNode = NULL; + } + } else { + if (timeSeconds > currentSeconds) { + previousNode = NULL; + } + break; // We have effectively run out of nodes to transverse, this is done! + } + } + + cNode->routeNode[0][LR_LAYER_INTERFLOW] = currentNode; + cNode->routeCNode[0][LR_LAYER_INTERFLOW] = (currentNode) ? &(lrNodes[currentNode->modelIndex]) : NULL; + cNode->routeNode[1][LR_LAYER_INTERFLOW] = previousNode; + cNode->routeCNode[1][LR_LAYER_INTERFLOW] = (previousNode) ? &(lrNodes[previousNode->modelIndex]) : NULL; + if ((currentSeconds - previousSeconds) > 0) { + cNode->routeAmount[0][LR_LAYER_INTERFLOW] = (timeSeconds - previousSeconds) / (currentSeconds - previousSeconds); + cNode->routeAmount[1][LR_LAYER_INTERFLOW] = 1.0 - cNode->routeAmount[0][LR_LAYER_INTERFLOW]; + } + } +} + diff --git a/src/LinearRoute.h b/src/LinearRoute.h new file mode 100755 index 0000000..56c208b --- /dev/null +++ b/src/LinearRoute.h @@ -0,0 +1,48 @@ +#ifndef LR_MODEL_H +#define LR_MODEL_H + +#include "ModelBase.h" + +enum LR_LAYER { + LR_LAYER_OVERLAND, + LR_LAYER_INTERFLOW, + LR_LAYER_QTY, +}; + +struct LRGridNode : BasicGridNode { + float params[PARAM_LINEAR_QTY]; + + double slopeSqrt; + + double nexTime[LR_LAYER_QTY]; // This is a by product of computing cell routing + LRGridNode *routeCNode[2][LR_LAYER_QTY]; // This is the node we route water to + GridNode *routeNode[2][LR_LAYER_QTY]; + double routeAmount[2][LR_LAYER_QTY]; + double incomingWater[LR_LAYER_QTY]; + + double reservoirs[LR_LAYER_QTY]; // CREST has two excess storage reservoirs (overland & interflow) +}; + +class LRRoute : public RoutingModel { + + public: + LRRoute(); + ~LRRoute(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeStates(TimeVar *beginTime, char *statePath, std::vector<float> *fastFlow, std::vector<float> *slowFlow); + void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter); + bool Route(float stepHours, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *discharge); + float GetMaxSpeed() { return maxSpeed; } + private: + void RouteInt(GridNode *node, LRGridNode *cNode, float fastFlow, float slowFlow); + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeRouting(float timeSeconds); + float SetObsInflow(long index, float inflow); + + std::vector<GridNode> *nodes; + std::vector<LRGridNode> lrNodes; + float maxSpeed; + bool initialized; +}; + +#endif diff --git a/src/MRMSConvert.cpp b/src/MRMSConvert.cpp new file mode 100644 index 0000000..5fff868 --- /dev/null +++ b/src/MRMSConvert.cpp @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "MRMSGrid.h" +#include "TifGrid.h" + +int main(int argc, char *argv[]) { + + if (argc != 3) { + printf("Use this program as MRMSConvert <input_filename> <output_filename>\n"); + return 1; + } + + char *filename = argv[1]; + char *outputfile = argv[2]; + + FloatGrid *precipGrid = ReadFloatMRMSGrid(filename); + + if (!precipGrid) { + printf("Failed to open file %s\n", filename); + return 1; + } + + WriteFloatTifGrid(outputfile, precipGrid); + + return 0; +} diff --git a/src/MRMSGrid.cpp b/src/MRMSGrid.cpp new file mode 100755 index 0000000..da377dc --- /dev/null +++ b/src/MRMSGrid.cpp @@ -0,0 +1,148 @@ +#include <cstdio> +#include <zlib.h> +#include <math.h> +#include "Messages.h" +#include "MRMSGrid.h" + +FloatGrid *ReadFloatMRMSGrid(char *file, FloatGrid *grid) { + + gzFile fileH; + + fileH = gzopen(file, "rb"); + if (fileH == NULL) { + return NULL; + } + + short int *binary_data = 0; + float nw_lon, nw_lat; + float dx;//, dy; + + MRMSHeader2D header; + if (gzread(fileH, &header, sizeof(MRMSHeader2D)) != sizeof(MRMSHeader2D)) { + WARNING_LOGF("MRMS file %s corrupt? (missing header)", file); + gzclose(fileH); + return NULL; + } + + if (gzseek(fileH, (header.nradars - 1) * 4, SEEK_CUR) == -1) { + WARNING_LOGF("MRMS file %s corrupt? (missing header radars)", file); + gzclose(fileH); + return NULL; + } + + + /*-------------------------*/ + /*** 3. Read binary data ***/ + /*-------------------------*/ + + int num = header.nx*header.ny; + binary_data = new short int[num]; + + if (!binary_data) { + WARNING_LOGF("MRMS file %s too large (out of memory) with %i points", file, num); + gzclose(fileH); + return NULL; + } + + //read data array + if (gzread(fileH,binary_data,num*sizeof(short int)) != num*(int)(sizeof(short int))) { + WARNING_LOGF("MRMS file %s corrupt?", file); + delete [] binary_data; + gzclose(fileH); + return NULL; + } + + gzclose(fileH); + + float *__restrict__ backingStore = new float[num]; + const float scalef = (float)header.var_scale; + int li = 0; + /*#pragma omp parallel for + for (li = 0; li < num; li += 4) { + backingStore[li] = ((float)binary_data[li]) / scalef; + backingStore[li+1] = ((float)binary_data[li+1]) / scalef; + backingStore[li+2] = ((float)binary_data[li+2]) / scalef; + backingStore[li+3] = ((float)binary_data[li+3]) / scalef; + } + */ + + bool badFile = false; + + //#pragma omp parallel for + for (li = 0; li < num; li++) { + backingStore[li] = ((float)binary_data[li]) / scalef; + } + + /*#pragma omp parallel for + for (li = 0; li < num; li++) { + if (backingStore[li] > 500.0) { + badFile = true; + } + }*/ + + dx = header.dx/float(header.dxy_scale); + //dy = header.dy/float(header.dxy_scale); + nw_lon = (float)header.nw_lon/(float)header.map_scale - (dx / 2.0); + nw_lat = (float)header.nw_lat/(float)header.map_scale - (dx / 2.0); + if (!grid) { + grid = new FloatGrid(); + grid->numCols = header.nx; + grid->numRows = header.ny; + grid->cellSize = dx; + grid->extent.top = nw_lat; + grid->extent.left = nw_lon; + grid->backingStore = backingStore; + grid->data = new float*[grid->numRows](); + if (!grid->data) { + WARNING_LOGF("MRMS file %s too large (out of memory) with %li rows", file, grid->numRows); + delete [] binary_data; + delete grid; + return NULL; + } + grid->noData = -999.0; + const long numRows = grid->numRows; + const int nX = header.nx; + for (long i = 0; i < numRows; i++) { + int realI = numRows - i - 1; + int index = realI*nX; + grid->data[i] = &(backingStore[index]); + } + } + + + /*#pragma omp parallel for + for (long i = 0; i < grid->numRows; i++) { + #pragma omp parallel for + for (int j = 0; j < grid->numCols; j++) { + int realI = grid->numRows - i - 1; + int index = realI*nx + j; + float floatData = 0; + floatData = ((float)binary_data[index]) / (float)var_scale; + grid->data[i][j] = floatData; + if (floatData > 500.0) { + badFile = true; + } + } + }*/ + + delete [] binary_data; + + if (badFile) { + printf("Rejecting %s for values > 500.0 ", file); + delete grid; + return NULL; + } + + //Fill in the rest of the BoundingBox + grid->extent.bottom = grid->extent.top - grid->numRows*grid->cellSize; + grid->extent.right = grid->extent.left + grid->numCols*grid->cellSize; + + return grid; + +} + +FloatGrid *ReadFloatMRMSGrid(char *file) { + + return ReadFloatMRMSGrid(file, NULL); + +} diff --git a/src/MRMSGrid.h b/src/MRMSGrid.h new file mode 100755 index 0000000..4612c18 --- /dev/null +++ b/src/MRMSGrid.h @@ -0,0 +1,44 @@ +#ifndef MRMS_GRID_H +#define MRMS_GRID_H + +#include "Grid.h" + +#pragma pack(push) +#pragma pack(1) +struct MRMSHeader2D { + int yr; + int mo; + int day; + int hr; + int min; + int sec; + int nx; + int ny; + int nz; + char projection[4]; + int map_scale; + int trulat1; + int trulat2; + int trulon; + int nw_lon; + int nw_lat; + int xy_scale; + int dx; + int dy; + int dxy_scale; + int grid_height; + int z_scale; + int placeholders[10]; + char temp_varname[20]; + char temp_varunit[6]; + int var_scale; + int missing_val; + int nradars; + char radar_id[4]; +}; +#pragma pack(pop) + +FloatGrid *ReadFloatMRMSGrid(char *file, FloatGrid *grid); +FloatGrid *ReadFloatMRMSGrid(char *file); + +#endif diff --git a/src/MRMSSum.cpp b/src/MRMSSum.cpp new file mode 100644 index 0000000..d39a4e8 --- /dev/null +++ b/src/MRMSSum.cpp @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "MRMSGrid.h" +#include "TifGrid.h" + +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> + +int main(int argc, char** argv) { + struct dirent *dp; + DIR *dfd; + + char *dir ; + dir = argv[1] ; + + if ( argc == 1 ) { + printf("Usage: %s dirname\n",argv[0]); + return 0; + } + + if ((dfd = opendir(dir)) == NULL) { + fprintf(stderr, "Can't open %s\n", dir); + return 0; + } + + char filename_qfd[100] ; + char new_name_qfd[100] ; + +FloatGrid *sumGrid = ReadFloatTifGrid("zero.tif"); + + while ((dp = readdir(dfd)) != NULL) { + struct stat stbuf ; + sprintf( filename_qfd , "%s/%s",dir,dp->d_name) ; + if( stat(filename_qfd,&stbuf ) == -1 ) { + printf("Unable to stat file: %s\n",filename_qfd) ; + continue ; + } + + if ( ( stbuf.st_mode & S_IFMT ) == S_IFDIR ) + { + continue; + // Skip directories + } + else + { + + printf("%s\n", filename_qfd); + FloatGrid *precipGrid = ReadFloatMRMSGrid(filename_qfd); + if (!precipGrid || precipGrid->numRows != sumGrid->numRows || precipGrid->numCols != sumGrid->numCols) { + if (precipGrid) { + delete precipGrid; + } + continue; + } + for (long y = 0; y < sumGrid->numRows; y++) { + for (long x = 0; x < sumGrid->numCols; x++) { + if (precipGrid->data[y][x] > 0.0) { + sumGrid->data[y][x] += (precipGrid->data[y][x]/12.0); + } + } + } + delete precipGrid; + } + } + + WriteFloatTifGrid("total.tif", sumGrid); + return 0; +} diff --git a/src/Messages.h b/src/Messages.h new file mode 100755 index 0000000..63c2346 --- /dev/null +++ b/src/Messages.h @@ -0,0 +1,30 @@ +#ifndef MESSAGES_H +#define MESSAGES_H + +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_RESET "\x1b[0m" + +#ifndef _WIN32 +#define LOGFR(...) printf(__VA_ARGS__) +#define NORMAL_LOGF(x, ...) printf(x, __VA_ARGS__) +#define DEBUG_LOGF(x, ...) LOGFR(ANSI_COLOR_YELLOW "DEBUG:" __FILE__ "(%i): " ANSI_COLOR_RESET x "\n", __LINE__, __VA_ARGS__) +#define INFO_LOGF(x, ...) LOGFR(ANSI_COLOR_GREEN "INFO:" __FILE__ "(%i): " ANSI_COLOR_RESET x "\n", __LINE__, __VA_ARGS__) +#define WARNING_LOGF(x, ...) LOGFR(ANSI_COLOR_YELLOW "WARNING:" __FILE__ "(%i): " ANSI_COLOR_RESET x "\n", __LINE__, __VA_ARGS__) +#define ERROR_LOG(x) LOGFR(ANSI_COLOR_RED "ERROR:" __FILE__ "(%i): " ANSI_COLOR_RESET x "\n", __LINE__) +#define ERROR_LOGF(x, ...) LOGFR(ANSI_COLOR_RED "ERROR:" __FILE__ "(%i): " ANSI_COLOR_RESET x "\n", __LINE__, __VA_ARGS__) +#else +#include "EF5Windows.h" +#define NORMAL_LOGF(x, ...) addConsoleText(NORMAL, x, __VA_ARGS__) +#define DEBUG_LOGF(x, ...) addConsoleText(INFOFMATION, x, __VA_ARGS__) +#define INFO_LOGF(x, ...) addConsoleText(INFORMATION, x, __VA_ARGS__) +#define WARNING_LOGF(x, ...) addConsoleText(WARNING, x, __VA_ARGS__) +#define ERROR_LOG(x) addConsoleText(FATAL, "%s", x) +#define ERROR_LOGF(x, ...) addConsoleText(FATAL, x, __VA_ARGS__) +#endif + +#endif diff --git a/src/Model.cpp b/src/Model.cpp new file mode 100755 index 0000000..8049e64 --- /dev/null +++ b/src/Model.cpp @@ -0,0 +1,331 @@ +#include "Model.h" + +const char *runStyleStrings[] = { + "simu", + "simu_rp", + "cali_ars", + "cali_dream", + "clip_basin", + "clip_gauge", + "make_basic", + "basin_avg", +}; + +const char *modelStrings[] = { + #undef ADDMODEL + #define ADDMODEL(a, b) a, + #include "Models.tbl" + #undef ADDMODEL + #define ADDMODEL(a, b) +}; + +const char *modelParamSetStrings[] = { + #undef ADDMODEL + #define ADDMODEL(a, b) a"paramset", + #include "Models.tbl" + #undef ADDMODEL + #define ADDMODEL(a, b) +}; + +const char *modelCaliParamStrings[] = { + #undef ADDMODEL + #define ADDMODEL(a, b) a"caliparams", + #include "Models.tbl" + #undef ADDMODEL + #define ADDMODEL(a, b) +}; + +// Order of models must match that in Models.tbl + +const char **modelParamStrings[] = { + (const char *[]){ + #undef ADDPARAMHP + #define ADDPARAMHP(a, b) a, + #include "Models.tbl" + #undef ADDPARAMHP + #define ADDPARAMHP(a, b) + + }, + + (const char *[]){ + #undef ADDPARAMCREST + #define ADDPARAMCREST(a, b) a, + #include "Models.tbl" + #undef ADDPARAMCREST + #define ADDPARAMCREST(a, b) + + }, + + (const char *[]){ + #undef ADDPARAMHYMOD + #define ADDPARAMHYMOD(a, b) a, + #include "Models.tbl" + #undef ADDPARAMHYMOD + #define ADDPARAMHYMOD(a, b) + + }, + + (const char *[]){ + #undef ADDPARAMSAC + #define ADDPARAMSAC(a, b) a, + #include "Models.tbl" + #undef ADDPARAMSAC + #define ADDPARAMSAC(a, b) + + }, + +}; + +// Order of models must match that in Models.tbl + +const char **modelParamGridStrings[] = { + (const char *[]){ + #undef ADDPARAMHP + #define ADDPARAMHP(a, b) a"_grid", + #include "Models.tbl" + #undef ADDPARAMHP + #define ADDPARAMHP(a, b) + }, + + (const char *[]){ + #undef ADDPARAMCREST + #define ADDPARAMCREST(a, b) a"_grid", + #include "Models.tbl" + #undef ADDPARAMCREST + #define ADDPARAMCREST(a, b) + + }, + + (const char *[]){ + #undef ADDPARAMHYMOD + #define ADDPARAMHYMOD(a, b) a"_grid", + #include "Models.tbl" + #undef ADDPARAMHYMOD + #define ADDPARAMHYMOD(a, b) + + }, + + (const char *[]){ + #undef ADDPARAMSAC + #define ADDPARAMSAC(a, b) a"_grid", + #include "Models.tbl" + #undef ADDPARAMSAC + #define ADDPARAMSAC(a, b) + }, + +}; + + +const int numModelParams[] = { + #undef ADDMODEL + #define ADDMODEL(a, b) PARAM_ ##b ##_QTY, + #include "Models.tbl" + #undef ADDMODEL + #define ADDMODEL(a, b) +}; + + + +const char *routeStrings[] = { +#undef ADDROUTE +#define ADDROUTE(a, b) a, +#include "Models.tbl" +#undef ADDROUTE +#define ADDROUTE(a, b) +}; + +const char *routeParamSetStrings[] = { +#undef ADDROUTE +#define ADDROUTE(a, b) a"paramset", +#include "Models.tbl" +#undef ADDROUTE +#define ADDROUTE(a, b) +}; + +const char *routeCaliParamStrings[] = { +#undef ADDROUTE +#define ADDROUTE(a, b) a"caliparams", +#include "Models.tbl" +#undef ADDROUTE +#define ADDROUTE(a, b) +}; + +const char **routeParamStrings[] = { + (const char *[]){ +#undef ADDPARAMLINEAR +#define ADDPARAMLINEAR(a, b) a, +#include "Models.tbl" +#undef ADDPARAMLINEAR +#define ADDPARAMLINEAR(a, b) + + }, + + (const char *[]){ +#undef ADDPARAMKINEMATIC +#define ADDPARAMKINEMATIC(a, b) a, +#include "Models.tbl" +#undef ADDPARAMKINEMATIC +#define ADDPARAMKINEMATIC(a, b) + + }, + +}; + +const char **routeParamGridStrings[] = { + (const char *[]){ +#undef ADDPARAMLINEAR +#define ADDPARAMLINEAR(a, b) a"_grid", +#include "Models.tbl" +#undef ADDPARAMLINEAR +#define ADDPARAMLINEAR(a, b) + + }, + + (const char *[]){ +#undef ADDPARAMKINEMATIC +#define ADDPARAMKINEMATIC(a, b) a"_grid", +#include "Models.tbl" +#undef ADDPARAMKINEMATIC +#define ADDPARAMKINEMATIC(a, b) + + }, +}; + +const int numRouteParams[] = { +#undef ADDROUTE +#define ADDROUTE(a, b) PARAM_ ##b ##_QTY, +#include "Models.tbl" +#undef ADDROUTE +#define ADDROUTE(a, b) +}; + + + + +const char *snowStrings[] = { +#undef ADDSNOW +#define ADDSNOW(a, b) a, +#include "Models.tbl" +#undef ADDSNOW +#define ADDSNOW(a, b) +}; + +const char *snowParamSetStrings[] = { +#undef ADDSNOW +#define ADDSNOW(a, b) a"paramset", +#include "Models.tbl" +#undef ADDSNOW +#define ADDSNOW(a, b) +}; + +const char *snowCaliParamStrings[] = { +#undef ADDSNOW +#define ADDSNOW(a, b) a"caliparams", +#include "Models.tbl" +#undef ADDSNOW +#define ADDSNOW(a, b) +}; + +const char **snowParamStrings[] = { + (const char *[]){ +#undef ADDPARAMSNOW17 +#define ADDPARAMSNOW17(a, b) a, +#include "Models.tbl" +#undef ADDPARAMSNOW17 +#define ADDPARAMSNOW17(a, b) + + }, +}; + +const char **snowParamGridStrings[] = { + (const char *[]){ +#undef ADDPARAMSNOW17 +#define ADDPARAMSNOW17(a, b) a"_grid", +#include "Models.tbl" +#undef ADDPARAMSNOW17 +#define ADDPARAMSNOW17(a, b) + + }, + +}; + +const int numSnowParams[] = { +#undef ADDSNOW +#define ADDSNOW(a, b) PARAM_ ##b ##_QTY, +#include "Models.tbl" +#undef ADDSNOW +#define ADDSNOW(a, b) +}; + +const char *inundationStrings[] = { +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) a, +#include "Models.tbl" +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) +}; + +const char *inundationParamSetStrings[] = { +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) a"paramset", +#include "Models.tbl" +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) +}; + +const char *inundationCaliParamStrings[] = { +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) a"caliparams", +#include "Models.tbl" +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) +}; + +const char **inundationParamStrings[] = { + (const char *[]){ +#undef ADDPARAMSI +#define ADDPARAMSI(a, b) a, +#include "Models.tbl" +#undef ADDPARAMSI +#define ADDPARAMSI(a, b) + + }, + + (const char *[]){ +#undef ADDPARAMVCI +#define ADDPARAMVCI(a, b) a, +#include "Models.tbl" +#undef ADDPARAMVCI +#define ADDPARAMVCI(a, b) + + }, +}; + +const char **inundationParamGridStrings[] = { + (const char *[]){ +#undef ADDPARAMSI +#define ADDPARAMSI(a, b) a"_grid", +#include "Models.tbl" +#undef ADDPARAMSI +#define ADDPARAMSI(a, b) + + }, + + (const char *[]){ +#undef ADDPARAMVCI +#define ADDPARAMVCI(a, b) a"_grid", +#include "Models.tbl" +#undef ADDPARAMVCI +#define ADDPARAMVCI(a, b) + + }, + +}; + +const int numInundationParams[] = { +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) PARAM_ ##b ##_QTY, +#include "Models.tbl" +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) +}; diff --git a/src/Model.h b/src/Model.h new file mode 100755 index 0000000..41aa151 --- /dev/null +++ b/src/Model.h @@ -0,0 +1,191 @@ +#ifndef MODEL_H +#define MODEL_H + +#define ADDMODEL(a, b) +#define ADDPARAMCREST(a, b) +#define ADDPARAMHYMOD(a, b) +#define ADDPARAMSAC(a, b) +#define ADDPARAMHP(a, b) +#define ADDROUTE(a, b) +#define ADDPARAMLINEAR(a, b) +#define ADDPARAMKINEMATIC(a, b) +#define ADDSNOW(a, b) +#define ADDPARAMSNOW17(a, b) +#define ADDINUNDATION(a, b) +#define ADDPARAMSI(a, b) +#define ADDPARAMVCI(a, b) + +enum RUNSTYLE { + STYLE_SIMU, + STYLE_SIMU_RP, + STYLE_CALI_ARS, + STYLE_CALI_DREAM, + STYLE_CLIP_BASIN, + STYLE_CLIP_GAUGE, + STYLE_MAKE_BASIC, + STYLE_BASIN_AVG, + STYLE_QTY, +}; + +enum MODELS { +#undef ADDMODEL +#define ADDMODEL(a, b) MODEL_##b, +#include "Models.tbl" +#undef ADDMODEL +#define ADDMODEL(a, b) + + MODEL_QTY, +}; + +enum CREST_PARAMS { +#undef ADDPARAMCREST +#define ADDPARAMCREST(a, b) PARAM_CREST_##b, +#include "Models.tbl" +#undef ADDPARAMCREST +#define ADDPARAMCREST(a, b) + + PARAM_CREST_QTY, +}; + +enum HYMOD_PARAMS { +#undef ADDPARAMHYMOD +#define ADDPARAMHYMOD(a, b) PARAM_HYMOD_##b, +#include "Models.tbl" +#undef ADDPARAMHYMOD +#define ADDPARAMHYMOD(a, b) + + PARAM_HYMOD_QTY, +}; + +enum SAC_PARAMS { +#undef ADDPARAMSAC +#define ADDPARAMSAC(a, b) PARAM_SAC_##b, +#include "Models.tbl" +#undef ADDPARAMSAC +#define ADDPARAMSAC(a, b) + + PARAM_SAC_QTY, +}; + +enum HP_PARAMS { +#undef ADDPARAMHP +#define ADDPARAMHP(a, b) PARAM_HP_##b, +#include "Models.tbl" +#undef ADDPARAMHP +#define ADDPARAMHP(a, b) + + PARAM_HP_QTY, +}; + +enum ROUTES { +#undef ADDROUTE +#define ADDROUTE(a, b) ROUTE_##b, +#include "Models.tbl" +#undef ADDROUTE +#define ADDROUTE(a, b) + + ROUTE_QTY, +}; + +enum LINEAR_PARAMS { +#undef ADDPARAMLINEAR +#define ADDPARAMLINEAR(a, b) PARAM_LINEAR_##b, +#include "Models.tbl" +#undef ADDPARAMLINEAR +#define ADDPARAMLINEAR(a, b) + + PARAM_LINEAR_QTY, +}; + +enum KINEMATIC_PARAMS { +#undef ADDPARAMKINEMATIC +#define ADDPARAMKINEMATIC(a, b) PARAM_KINEMATIC_##b, +#include "Models.tbl" +#undef ADDPARAMKINEMATIC +#define ADDPARAMKINEMATIC(a, b) + + PARAM_KINEMATIC_QTY, +}; + +enum SNOWS { +#undef ADDSNOW +#define ADDSNOW(a, b) SNOW_##b, +#include "Models.tbl" +#undef ADDSNOW +#define ADDSNOW(a, b) + + SNOW_QTY, +}; + +enum SNOW17_PARAMS { +#undef ADDPARAMSNOW17 +#define ADDPARAMSNOW17(a, b) PARAM_SNOW17_##b, +#include "Models.tbl" +#undef ADDPARAMSNOW17 +#define ADDPARAMSNOW17(a, b) + + PARAM_SNOW17_QTY, +}; + +enum INUNDATIONS { +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) INUNDATION_##b, +#include "Models.tbl" +#undef ADDINUNDATION +#define ADDINUNDATION(a, b) + + INUNDATION_QTY, +}; + +enum SI_PARAMS { +#undef ADDPARAMSI +#define ADDPARAMSI(a, b) PARAM_SI_##b, +#include "Models.tbl" +#undef ADDPARAMSI +#define ADDPARAMSI(a, b) + + PARAM_SI_QTY, +}; + +enum VCI_PARAMS { +#undef ADDPARAMVCI +#define ADDPARAMVCI(a, b) PARAM_VCI_##b, +#include "Models.tbl" +#undef ADDPARAMVCI +#define ADDPARAMVCI(a, b) + + PARAM_VCI_QTY, +}; + +extern const char *runStyleStrings[]; +extern const char *modelStrings[]; +extern const char *modelParamSetStrings[]; +extern const char *modelCaliParamStrings[]; +extern const char **modelParamStrings[]; +extern const char **modelParamGridStrings[]; +extern const int numModelParams[]; + +extern const char *routeStrings[]; +extern const char *routeParamSetStrings[]; +extern const char *routeCaliParamStrings[]; +extern const char **routeParamStrings[]; +extern const char **routeParamGridStrings[]; +extern const int numRouteParams[]; + +extern const char *snowStrings[]; +extern const char *snowParamSetStrings[]; +extern const char *snowCaliParamStrings[]; +extern const char **snowParamStrings[]; +extern const char **snowParamGridStrings[]; +extern const int numSnowParams[]; + +extern const char *inundationStrings[]; +extern const char *inundationParamSetStrings[]; +extern const char *inundationCaliParamStrings[]; +extern const char **inundationParamStrings[]; +extern const char **inundationParamGridStrings[]; +extern const int numInundationParams[]; + +#define IsCalibrationRunStyle(style) ((style) == STYLE_CALI_ARS || (style) == STYLE_CALI_DREAM) + +#endif diff --git a/src/ModelBase.h b/src/ModelBase.h new file mode 100755 index 0000000..6c52a25 --- /dev/null +++ b/src/ModelBase.h @@ -0,0 +1,62 @@ +#ifndef MODELBASE_H +#define MODELBASE_H + +#include <vector> +#include "BasicGrids.h" +#include "ParamSetConfigSection.h" +#include "TimeUnit.h" +#include "GridWriterFull.h" + +class Model { + + public: + virtual bool InitializeModel(TimeUnit *timeStep, std::vector<GridNode> *nodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) = 0; + virtual void InitializeStates(TimeVar *beginTime, char *statePath) = 0; + virtual void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) = 0; + virtual bool RunTimeStep(long index, float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *discharge, std::vector<float> *soilMoisture) = 0; + virtual bool IsLumped() = 0; + virtual const char *GetName() = 0; +}; + +class WaterBalanceModel { + +public: + virtual bool InitializeModel(std::vector<GridNode> *nodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) = 0; + virtual void InitializeStates(TimeVar *beginTime, char *statePath) = 0; + virtual void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) = 0; + virtual bool WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture) = 0; + virtual bool IsLumped() = 0; + virtual const char *GetName() = 0; +}; + +class RoutingModel { + +public: + virtual bool InitializeModel(std::vector<GridNode> *nodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) = 0; + virtual void InitializeStates(TimeVar *beginTime, char *statePath, std::vector<float> *fastFlow, std::vector<float> *slowFlow) = 0; + virtual void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) = 0; + virtual bool Route(float stepHours, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *discharge) = 0; + virtual float GetMaxSpeed() = 0; + virtual float SetObsInflow(long index, float inflow) = 0; +}; + +class SnowModel { + +public: + virtual bool InitializeModel(std::vector<GridNode> *nodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) = 0; + virtual void InitializeStates(TimeVar *beginTime, char *statePath) = 0; + virtual void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) = 0; + virtual bool SnowBalance(float jday, float stepHours, std::vector<float> *precip, std::vector<float> *temp, std::vector<float> *melt, std::vector<float> *swe) = 0; + virtual const char *GetName() = 0; +}; + +class InundationModel { + +public: + virtual bool InitializeModel(std::vector<GridNode> *nodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) = 0; + virtual bool Inundation(std::vector<float> *discharge, std::vector<float> *depth) = 0; + virtual const char *GetName() = 0; +}; + + +#endif diff --git a/src/Models.tbl b/src/Models.tbl new file mode 100755 index 0000000..75c3c07 --- /dev/null +++ b/src/Models.tbl @@ -0,0 +1,84 @@ +ADDMODEL("hp", HP) +ADDPARAMHP("precip", PRECIP) +ADDPARAMHP("split", SPLIT) + +ADDMODEL("crest", CREST) +ADDPARAMCREST("wm", WM) +ADDPARAMCREST("b", B) +ADDPARAMCREST("im", IM) +ADDPARAMCREST("ke", KE) +ADDPARAMCREST("fc", FC) +ADDPARAMCREST("iwu", IWU) + +ADDMODEL("hymod", HYMOD) +ADDPARAMHYMOD("huz", HUZ) +ADDPARAMHYMOD("b", B) +ADDPARAMHYMOD("alp", ALP) +ADDPARAMHYMOD("nq", NQ) +ADDPARAMHYMOD("kq", KQ) +ADDPARAMHYMOD("ks", KS) +ADDPARAMHYMOD("xcuz", XCUZ) +ADDPARAMHYMOD("xq", XQ) +ADDPARAMHYMOD("xs", XS) +ADDPARAMHYMOD("precip", PRECIP) + +ADDMODEL("sac", SAC) +ADDPARAMSAC("uztwm", UZTWM) +ADDPARAMSAC("uzfwm", UZFWM) +ADDPARAMSAC("uzk", UZK) +ADDPARAMSAC("pctim", PCTIM) +ADDPARAMSAC("adimp", ADIMP) +ADDPARAMSAC("riva", RIVA) +ADDPARAMSAC("zperc", ZPERC) +ADDPARAMSAC("rexp", REXP) +ADDPARAMSAC("lztwm", LZTWM) +ADDPARAMSAC("lzfsm", LZFSM) +ADDPARAMSAC("lzfpm", LZFPM) +ADDPARAMSAC("lzsk", LZSK) +ADDPARAMSAC("lzpk", LZPK) +ADDPARAMSAC("pfree", PFREE) +ADDPARAMSAC("side", SIDE) +ADDPARAMSAC("rserv", RSERV) +ADDPARAMSAC("uztwc", UZTWC) +ADDPARAMSAC("uzfwc", UZFWC) +ADDPARAMSAC("adimc", ADIMC) +ADDPARAMSAC("lztwc", LZTWC) +ADDPARAMSAC("lzfsc", LZFSC) +ADDPARAMSAC("lzfpc", LZFPC) + +ADDROUTE("lr", LINEAR) +ADDPARAMLINEAR("coem", COEM) +ADDPARAMLINEAR("river", RIVER) +ADDPARAMLINEAR("under", UNDER) +ADDPARAMLINEAR("leako", LEAKO) +ADDPARAMLINEAR("leaki", LEAKI) +ADDPARAMLINEAR("th", TH) +ADDPARAMLINEAR("iso", ISO) +ADDPARAMLINEAR("isu", ISU) + +ADDROUTE("kw", KINEMATIC) +ADDPARAMKINEMATIC("under", UNDER) +ADDPARAMKINEMATIC("leaki", LEAKI) +ADDPARAMKINEMATIC("th", TH) +ADDPARAMKINEMATIC("isu", ISU) +ADDPARAMKINEMATIC("alpha", ALPHA) +ADDPARAMKINEMATIC("beta", BETA) +ADDPARAMKINEMATIC("alpha0", ALPHA0) + +ADDSNOW("snow17", SNOW17) +ADDPARAMSNOW17("uadj", UADJ) +ADDPARAMSNOW17("mbase", MBASE) +ADDPARAMSNOW17("mfmax", MFMAX) +ADDPARAMSNOW17("mfmin", MFMIN) +ADDPARAMSNOW17("tipm", TIPM) +ADDPARAMSNOW17("nmf", NMF) +ADDPARAMSNOW17("plwhc", PLWHC) +ADDPARAMSNOW17("scf", SCF) + +ADDINUNDATION("simpleinundation", SI) +ADDPARAMSI("alpha", ALPHA) +ADDPARAMSI("beta", BETA) + +ADDINUNDATION("vcinundation", VCI) +ADDPARAMVCI("alpha", ALPHA) +ADDPARAMVCI("beta", BETA) diff --git a/src/ObjectiveFunc.cpp b/src/ObjectiveFunc.cpp new file mode 100755 index 0000000..3f0b5c9 --- /dev/null +++ b/src/ObjectiveFunc.cpp @@ -0,0 +1,109 @@ +#include <cstdio> +#include <cmath> +#include <cstdlib> +#include "ObjectiveFunc.h" + +const char *objectiveStrings[] = { + "nsce", + "cc", + "sse" +}; + +const OBJECTIVE_GOAL objectiveGoals[] = { + OBJECTIVE_GOAL_MAXIMIZE, + OBJECTIVE_GOAL_MAXIMIZE, + OBJECTIVE_GOAL_MINIMIZE, +}; + +// Internal functions for calculating actual objective function scores +static float CalcNSCE(std::vector<float> *obs, std::vector<float> *sim); +static float CalcCC(std::vector<float> *obs, std::vector<float> *sim); +static float CalcSSE(std::vector<float> *obs, std::vector<float> *sim); + +// This is the main function for calculating objective functions, everything passes through here first. +float CalcObjFunc(std::vector<float> *obs, std::vector<float> *sim, OBJECTIVES obj) { + + switch (obj) { + case OBJECTIVE_NSCE: + return CalcNSCE(obs, sim); + case OBJECTIVE_CC: + return CalcCC(obs, sim); + case OBJECTIVE_SSE: + return CalcSSE(obs, sim); + default: + return 0; + } + +} + +float CalcNSCE(std::vector<float> *obs, std::vector<float> *sim) { + + float obsMean = 0, obsAcc = 0, simAcc = 0, validQs = 0; + size_t totalTimeSteps = obs->size(); + for (size_t tsIndex = 0; tsIndex < totalTimeSteps; tsIndex++) { + if ((*obs)[tsIndex] == (*obs)[tsIndex] && (*sim)[tsIndex] == (*sim)[tsIndex]) { + obsMean += (*obs)[tsIndex]; + validQs++; + } + } + + obsMean /= validQs; + + for (size_t tsIndex = 0; tsIndex < totalTimeSteps; tsIndex++) { + if ((*obs)[tsIndex] == (*obs)[tsIndex] && (*sim)[tsIndex] == (*sim)[tsIndex]) { + //printf("%f %f\n", (*obs)[tsIndex], (*sim)[tsIndex]); + obsAcc += powf((*obs)[tsIndex] - obsMean, 2.0); + simAcc += powf((*obs)[tsIndex] - (*sim)[tsIndex], 2.0); + } + } + + float result = 1.0 - (simAcc / obsAcc); + if (result == result) { + return result; + } else { + return -10000000000.0; + } +} + +float CalcCC(std::vector<float> *obs, std::vector<float> *sim) { + + float obsMean = 0, simMean = 0, obsAcc2 = 0, obsAcc = 0, simAcc = 0; + size_t validQs = 0, totalTimeSteps = obs->size(); + for (size_t tsIndex = 0; tsIndex < totalTimeSteps; tsIndex++) { + if ((*obs)[tsIndex] == (*obs)[tsIndex] && (*sim)[tsIndex] == (*sim)[tsIndex]) { + obsMean += (*obs)[tsIndex]; + simMean += (*sim)[tsIndex]; + validQs++; + } + } + + obsMean /= validQs; + simMean /= validQs; + + for (size_t tsIndex = 0; tsIndex < totalTimeSteps; tsIndex++) { + if ((*obs)[tsIndex] == (*obs)[tsIndex] && (*sim)[tsIndex] == (*sim)[tsIndex]) { + obsAcc += pow((*obs)[tsIndex] - obsMean, 2); + simAcc += pow((*sim)[tsIndex] - simMean, 2); + obsAcc2 += ( ((*obs)[tsIndex] - obsMean) * ((*sim)[tsIndex] - simMean) ); + } + } + + obsAcc = sqrt(obsAcc); + simAcc = sqrt(simAcc); + + return obsAcc2 / (obsAcc * simAcc); +} + +float CalcSSE(std::vector<float> *obs, std::vector<float> *sim) { + + float sse = 0; + size_t totalTimeSteps = obs->size(); + + for (size_t tsIndex = 0; tsIndex < totalTimeSteps; tsIndex++) { + if ((*obs)[tsIndex] == (*obs)[tsIndex] && (*sim)[tsIndex] == (*sim)[tsIndex]) { + sse += pow((*obs)[tsIndex] - (*sim)[tsIndex], 2); + } + } + + return sse; +} diff --git a/src/ObjectiveFunc.h b/src/ObjectiveFunc.h new file mode 100755 index 0000000..3dacae6 --- /dev/null +++ b/src/ObjectiveFunc.h @@ -0,0 +1,23 @@ +#ifndef OBJECTIVE_FUNC_H +#define OBJECTIVE_FUNC_H + +#include <vector> + +enum OBJECTIVES { + OBJECTIVE_NSCE, + OBJECTIVE_CC, + OBJECTIVE_SSE, + OBJECTIVE_QTY, +}; + +enum OBJECTIVE_GOAL { + OBJECTIVE_GOAL_MAXIMIZE, + OBJECTIVE_GOAL_MINIMIZE, +}; + +extern const char *objectiveStrings[]; +extern const OBJECTIVE_GOAL objectiveGoals[]; + +float CalcObjFunc(std::vector<float> *obs, std::vector<float> *sim, OBJECTIVES obj); + +#endif diff --git a/src/PETConfigSection.cpp b/src/PETConfigSection.cpp new file mode 100755 index 0000000..d0f46c9 --- /dev/null +++ b/src/PETConfigSection.cpp @@ -0,0 +1,100 @@ +#include <cstdio> +#include <cstring> +#include <string> +#include "Messages.h" +#include "PETConfigSection.h" + +std::map<std::string, PETConfigSection *> g_petConfigs; + +PETConfigSection::PETConfigSection() { + locSet = false; + freqSet = false; + nameSet = false; + typeSet = false; + unitSet = false; + isTemp = false; +} + +PETConfigSection::~PETConfigSection() { + +} + +DatedName *PETConfigSection::GetFileName() { + return &fileName; +} + +CONFIG_SEC_RET PETConfigSection::ProcessKeyValue(char *name, char *value) { + + if (!strcasecmp(name, "type")) { + SUPPORTED_PET_TYPES result = type.ParseType(value); + if (result == PET_TYPE_QTY) { + ERROR_LOGF("Unknown type option \"%s\"", value); + INFO_LOGF("Valid PET type options are \"%s\"", type.GetTypes()); + return INVALID_RESULT; + } + typeSet = true; + } else if (!strcasecmp(name, "unit")) { + bool result = unit.ParseUnit(value); + if (!result) { + if (!strcasecmp(value, "c")) { + isTemp = true; + result = true; + } + } + if (!result) { + ERROR_LOGF("Unknown unit option \"%s\"", value); + return INVALID_RESULT; + } + unitSet = true; + } else if (!strcasecmp(name, "freq")) { + SUPPORTED_TIME_UNITS result = freq.ParseUnit(value); + if (result == TIME_UNIT_QTY) { + ERROR_LOGF("Unknown frequency option \"%s\"", value); + return INVALID_RESULT; + } + freqSet = true; + } else if (!strcasecmp(name, "loc")) { + strcpy(loc, value); + locSet = true; + } else if (!strcasecmp(name, "name")) { + fileName.SetNameStr(value); + nameSet = true; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET PETConfigSection::ValidateSection() { + if (!typeSet) { + ERROR_LOG("The type was not specified"); + return INVALID_RESULT; + } else if (!unitSet) { + ERROR_LOG("The unit was not specified"); + return INVALID_RESULT; + } else if (!freqSet) { + ERROR_LOG("The frequency was not specified"); + return INVALID_RESULT; + } else if (!locSet) { + ERROR_LOG("The location was not specified"); + return INVALID_RESULT; + } else if (!nameSet) { + ERROR_LOG("The file name was not specified"); + return INVALID_RESULT; + } + + if (!fileName.ProcessNameLoose(&freq)) { + ERROR_LOG("The file name was specified with improper resolution"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +bool PETConfigSection::IsDuplicate(char *name) { + std::map<std::string, PETConfigSection *>::iterator itr = g_petConfigs.find(std::string(name)); + if (itr == g_petConfigs.end()) { + return false; + } else { + return true; + } +} + diff --git a/src/PETConfigSection.h b/src/PETConfigSection.h new file mode 100755 index 0000000..b715086 --- /dev/null +++ b/src/PETConfigSection.h @@ -0,0 +1,43 @@ +#ifndef CONFIG_PET_SECTION_H +#define CONFIG_PET_SECTION_H + +#include <map> +#include "Defines.h" +#include "TimeUnit.h" +#include "DistancePerTimeUnits.h" +#include "DatedName.h" +#include "PETType.h" +#include "ConfigSection.h" + +class PETConfigSection : public ConfigSection { + + public: + PETConfigSection(); + ~PETConfigSection(); + + DatedName *GetFileName(); + TimeUnit *GetFreq() { return &freq; } + char *GetLoc() { return loc; } + TimeUnit *GetUnitTime() { return unit.GetTime(); } + SUPPORTED_PET_TYPES GetType() { return type.GetType(); } + bool IsTemperature() { return isTemp; } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name); + + private: + bool locSet, freqSet, nameSet, unitSet, typeSet; + bool isTemp; + char loc[CONFIG_MAX_LEN]; + DatedName fileName; + TimeUnit freq; + DistancePerTimeUnits unit; + PETType type; + + +}; + +extern std::map<std::string, PETConfigSection *> g_petConfigs; + +#endif diff --git a/src/PETReader.cpp b/src/PETReader.cpp new file mode 100755 index 0000000..44967a6 --- /dev/null +++ b/src/PETReader.cpp @@ -0,0 +1,100 @@ +#include <cmath> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "AscGrid.h" +#include "BifGrid.h" +#include "TifGrid.h" +#include "PETReader.h" + +bool PETReader::Read(char *file, SUPPORTED_PET_TYPES type, std::vector<GridNode> *nodes, std::vector<float> *currentPET, float petConvert, bool isTemp, float jday, std::vector<float> *prevPET) { + if (!strcmp(lastPETFile, file)) { + if (prevPET) { + for (size_t i = 0; i < nodes->size(); i++) { + currentPET->at(i) = prevPET->at(i); + } + } + return true; // This is the same pet file that we read last time, we assume currentPET is still valid! + } + + strcpy(lastPETFile, file); + + FloatGrid *petGrid = NULL; + + switch (type) { + case PET_ASCII: + petGrid = ReadFloatAscGrid(file); + break; + case PET_BIF: + petGrid = ReadFloatBifGrid(file); + break; + case PET_TIF: + petGrid = ReadFloatTifGrid(file); + break; + default: + ERROR_LOG("Unsupported PET format!"); + break; + } + + if (!petGrid) { + // If the file is not found or something else is wrong we assume zero values + for (size_t i = 0; i < nodes->size(); i++) { + currentPET->at(i) = 0; + } + return false; + } + + // We have two options now... Either the pet grid & the basic grids are the same + // Or they are different! + + if (g_DEM->IsSpatialMatch(petGrid)) { + // The grids are the same! Our life is easy! + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (petGrid->data[node->y][node->x] > 0.0) { + currentPET->at(i) = petGrid->data[node->y][node->x] * petConvert; + } else { + currentPET->at(i) = 0.0; + } + } + + } else { + // The grids are different, we must do some resampling fun. + GridLoc pt; + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (petGrid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && petGrid->data[pt.y][pt.x] > 0.0) { + currentPET->at(i) = petGrid->data[pt.y][pt.x] * petConvert; + } else { + currentPET->at(i) = 0; + } + } + } + + // See if this is a temperature grid and if so convert it into PET using Hamon (1961). + if (isTemp) { + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (currentPET->at(i) <= 0 && currentPET->at(i) != petGrid->noData) { + currentPET->at(i) = 0; // Hey, its below freezing, no potential evaporation! + } else if (currentPET->at(i) != petGrid->noData) { + float lon, lat; + RefLoc pt; + g_DEM->GetRefLoc(node->x, node->y, &pt); + g_Projection->UnprojectPoint(pt.x, pt.y, &lon, &lat); + float e_s = 0.2749e8 * exp(-4278.6 / (currentPET->at(i) + 242.8)); + float delta = 0.4093 * sin(2 * PI * jday / 365 - 1.405); + float omega_s = acos(-tan(TORADIANS(lat)) * tan(delta)); + float H_t = 24 * omega_s / PI; + float E_t = 2.1 * pow(H_t, 2) * e_s / (currentPET->at(i) + 273.3); + //printf("(%f, %f) %f, %f, %f, %f, %f, %f\n", lat, lon, currentPET->at(i), e_s, delta, omega_s, H_t, E_t); + currentPET->at(i) = E_t / 24; // These E_t values are mm day ^ -1, we want mm h ^ -1 + } + } + } + + // We don't actually need to keep the PET grid in memory anymore + delete petGrid; + + return true; +} diff --git a/src/PETReader.h b/src/PETReader.h new file mode 100755 index 0000000..744160e --- /dev/null +++ b/src/PETReader.h @@ -0,0 +1,18 @@ +#ifndef PET_READER_H +#define PET_READER_H + +#include <vector> +#include "Defines.h" +#include "BasicGrids.h" +#include "PETType.h" + +class PETReader { + public: + bool Read(char *file, SUPPORTED_PET_TYPES type, std::vector<GridNode> *nodes, std::vector<float> *currentPET, float petConvert, bool isTemp, float jday, std::vector<float> *prevPET = NULL); + + private: + char lastPETFile[CONFIG_MAX_LEN*2]; + +}; + +#endif diff --git a/src/PETType.cpp b/src/PETType.cpp new file mode 100755 index 0000000..c3bc1b3 --- /dev/null +++ b/src/PETType.cpp @@ -0,0 +1,34 @@ +#include <cstring> +#include "PETType.h" + +const char *petTypeStrings[] = { + "asc", + "bif", + "tif", +}; + +SUPPORTED_PET_TYPES PETType::GetType() { + return type; +} + +SUPPORTED_PET_TYPES PETType::ParseType(char *typeStr) { + SUPPORTED_PET_TYPES result = PET_TYPE_QTY; + + for (int i = 0; i < PET_TYPE_QTY; i++) { + if (!strcasecmp(petTypeStrings[i], typeStr)) { + result = (SUPPORTED_PET_TYPES)i; + break; + } + } + + type = result; + + return result; + +} + +const char *PETType::GetTypes() { + return "ASC, BIF, TIF"; +} + + diff --git a/src/PETType.h b/src/PETType.h new file mode 100755 index 0000000..e4d8b32 --- /dev/null +++ b/src/PETType.h @@ -0,0 +1,24 @@ +#ifndef PET_TYPE_H +#define PET_TYPE_H + +enum SUPPORTED_PET_TYPES { + PET_ASCII, + PET_BIF, + PET_TIF, + PET_TYPE_QTY, +}; + +extern const char *petTypeStrings[]; + +class PETType { + + public: + SUPPORTED_PET_TYPES GetType(); + SUPPORTED_PET_TYPES ParseType(char *typeStr); + const char *GetTypes(); + + private: + SUPPORTED_PET_TYPES type; +}; + +#endif diff --git a/src/ParamSetConfigSection.cpp b/src/ParamSetConfigSection.cpp new file mode 100755 index 0000000..ab69585 --- /dev/null +++ b/src/ParamSetConfigSection.cpp @@ -0,0 +1,137 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "ParamSetConfigSection.h" + +std::map<std::string, ParamSetConfigSection *> g_paramSetConfigs[MODEL_QTY]; + +ParamSetConfigSection::ParamSetConfigSection(char *nameVal, MODELS modelVal) { + strcpy(name, nameVal); + currentGauge = NULL; + currentParams = NULL; + currentParamsSet = NULL; + model = modelVal; + paramGrids.resize(numModelParams[model]); +} + +ParamSetConfigSection::~ParamSetConfigSection() { + +} + +char *ParamSetConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET ParamSetConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numModelParams[model]; + + if (strcasecmp(name, "gauge") == 0) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", modelParamStrings[model][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + if (IsDuplicateGauge(itr->second)) { + ERROR_LOGF("Duplicate gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + currentGauge = itr->second; + currentParams = new float[numParams]; + currentParamsSet = new bool[numParams]; + memset(currentParams, 0, sizeof(float)*numParams); + memset(currentParamsSet, 0, sizeof(bool)*numParams); + } else { + + // Lets see if this belongs to a parameter grid + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, modelParamGridStrings[model][i]) == 0) { + paramGrids[i] = std::string(value); + return VALID_RESULT; + } + } + + if (!currentGauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + + //Lets see if this belongs to a parameter scalar + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, modelParamStrings[model][i]) == 0) { + + if (currentParamsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + currentParams[i] = atof(value); + currentParamsSet[i] = true; + + return VALID_RESULT; + } + } + + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET ParamSetConfigSection::ValidateSection() { + int numParams = numModelParams[model]; + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", modelParamStrings[model][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + + + return VALID_RESULT; +} + +bool ParamSetConfigSection::IsDuplicate(char *name, MODELS modelVal) { + std::map<std::string, ParamSetConfigSection *>::iterator itr = g_paramSetConfigs[modelVal].find(name); + if (itr == g_paramSetConfigs[modelVal].end()) { + return false; + } else { + return true; + } +} + +bool ParamSetConfigSection::IsDuplicateGauge(GaugeConfigSection *gaugeVal) { + std::map<GaugeConfigSection *, float *>::iterator itr = paramSettings.find(gaugeVal); + if (itr == paramSettings.end()) { + return false; + } else { + return true; + } +} diff --git a/src/ParamSetConfigSection.h b/src/ParamSetConfigSection.h new file mode 100755 index 0000000..cc05685 --- /dev/null +++ b/src/ParamSetConfigSection.h @@ -0,0 +1,40 @@ +#ifndef CONFIG_PARAMSET_SECTION_H +#define CONFIG_PARAMSET_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" + +class ParamSetConfigSection : public ConfigSection { + + public: + ParamSetConfigSection(char *nameVal, MODELS modelVal); + ~ParamSetConfigSection(); + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + std::map<GaugeConfigSection *, float *> *GetParamSettings() { return ¶mSettings; } + std::vector<std::string> *GetParamGrids() { return ¶mGrids; } + + static bool IsDuplicate(char *name, MODELS modelVal); + + private: + bool IsDuplicateGauge(GaugeConfigSection *); + + char name[CONFIG_MAX_LEN]; + MODELS model; + GaugeConfigSection *currentGauge; + float *currentParams; + bool *currentParamsSet; + std::map<GaugeConfigSection *, float *> paramSettings; + std::vector<std::string> paramGrids; + + +}; + +extern std::map<std::string, ParamSetConfigSection *> g_paramSetConfigs[]; + +#endif diff --git a/src/PrecipConfigSection.cpp b/src/PrecipConfigSection.cpp new file mode 100755 index 0000000..f12a46e --- /dev/null +++ b/src/PrecipConfigSection.cpp @@ -0,0 +1,92 @@ +#include <cstdio> +#include <cstring> +#include <string> +#include "Messages.h" +#include "PrecipConfigSection.h" + +std::map<std::string, PrecipConfigSection *> g_precipConfigs; + +PrecipConfigSection::PrecipConfigSection() { + locSet = false; + freqSet = false; + nameSet = false; + typeSet = false; + unitSet = false; +} + +PrecipConfigSection::~PrecipConfigSection() { + +} + +DatedName *PrecipConfigSection::GetFileName() { + return &fileName; +} + +CONFIG_SEC_RET PrecipConfigSection::ProcessKeyValue(char *name, char *value) { + + if (!strcasecmp(name, "type")) { + SUPPORTED_PRECIP_TYPES result = type.ParseType(value); + if (result == PRECIP_TYPE_QTY) { + ERROR_LOGF("Unknown type option \"%s\"", value); + INFO_LOGF("Valid precip type options are \"%s\"", type.GetTypes()); + return INVALID_RESULT; + } + typeSet = true; + } else if (!strcasecmp(name, "unit")) { + bool result = unit.ParseUnit(value); + if (!result) { + ERROR_LOGF("Unknown unit option \"%s\"", value); + return INVALID_RESULT; + } + unitSet = true; + } else if (!strcasecmp(name, "freq")) { + SUPPORTED_TIME_UNITS result = freq.ParseUnit(value); + if (result == TIME_UNIT_QTY) { + ERROR_LOGF("Unknown frequency option \"%s\"", value); + return INVALID_RESULT; + } + freqSet = true; + } else if (!strcasecmp(name, "loc")) { + strcpy(loc, value); + locSet = true; + } else if (!strcasecmp(name, "name")) { + fileName.SetNameStr(value); + nameSet = true; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET PrecipConfigSection::ValidateSection() { + if (!typeSet) { + ERROR_LOG("The type was not specified"); + return INVALID_RESULT; + } else if (!unitSet) { + ERROR_LOG("The unit was not specified"); + return INVALID_RESULT; + } else if (!freqSet) { + ERROR_LOG("The frequency was not specified"); + return INVALID_RESULT; + } else if (!locSet) { + ERROR_LOG("The location was not specified"); + return INVALID_RESULT; + } else if (!nameSet) { + ERROR_LOG("The file name was not specified"); + return INVALID_RESULT; + } + + if (!fileName.ProcessName(&freq)) { + ERROR_LOG("The file name was specified with improper resolution"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +bool PrecipConfigSection::IsDuplicate(char *name) { + std::map<std::string, PrecipConfigSection *>::iterator itr = g_precipConfigs.find(std::string(name)); + if (itr == g_precipConfigs.end()) { + return false; + } else { + return true; + } +} diff --git a/src/PrecipConfigSection.h b/src/PrecipConfigSection.h new file mode 100755 index 0000000..655123c --- /dev/null +++ b/src/PrecipConfigSection.h @@ -0,0 +1,41 @@ +#ifndef CONFIG_PRECIP_SECTION_H +#define CONFIG_PRECIP_SECTION_H + +#include <map> +#include "Defines.h" +#include "TimeUnit.h" +#include "DistancePerTimeUnits.h" +#include "DatedName.h" +#include "PrecipType.h" +#include "ConfigSection.h" + +class PrecipConfigSection : public ConfigSection { + + public: + PrecipConfigSection(); + ~PrecipConfigSection(); + + DatedName *GetFileName(); + char *GetLoc() { return loc; } + TimeUnit *GetFreq() { return &freq; } + TimeUnit *GetUnitTime() { return unit.GetTime(); } + SUPPORTED_PRECIP_TYPES GetType() { return type.GetType(); } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name); + + private: + bool locSet, freqSet, nameSet, unitSet, typeSet; + char loc[CONFIG_MAX_LEN]; + DatedName fileName; + TimeUnit freq; + DistancePerTimeUnits unit; + PrecipType type; + + +}; + +extern std::map<std::string, PrecipConfigSection *> g_precipConfigs; + +#endif diff --git a/src/PrecipReader.cpp b/src/PrecipReader.cpp new file mode 100755 index 0000000..7637565 --- /dev/null +++ b/src/PrecipReader.cpp @@ -0,0 +1,102 @@ +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "AscGrid.h" +#include "BifGrid.h" +#include "TifGrid.h" +#include "TRMMRTGrid.h" +#include "TRMMV6Grid.h" +#include "MRMSGrid.h" +#include "PrecipReader.h" + +bool PrecipReader::Read(char *file, SUPPORTED_PRECIP_TYPES type, std::vector<GridNode> *nodes, std::vector<float> *currentPrecip, float precipConvert, std::vector<float> *prevPrecip, bool hasQPF) { + if (!strcmp(lastPrecipFile, file)) { + if (prevPrecip) { + for (size_t i = 0; i < nodes->size(); i++) { + currentPrecip->at(i) = prevPrecip->at(i); + } + } + return true; // This is the same precip file that we read last time, we assume currentPrecip is still valid! + } + + if (!hasQPF) { + // Update this here so we recheck for missing files & don't recheck for forecast precip + strcpy(lastPrecipFile, file); + } + + //static FloatGrid *precipGrid = NULL; + FloatGrid *precipGrid = NULL; + + switch (type) { + case PRECIP_ASCII: + precipGrid = ReadFloatAscGrid(file); + break; + case PRECIP_BIF: + precipGrid = ReadFloatBifGrid(file); + break; + case PRECIP_TIF: + precipGrid = ReadFloatTifGrid(file); + break; + case PRECIP_MRMS: + precipGrid = ReadFloatMRMSGrid(file); + break; + case PRECIP_TRMMRT: + precipGrid = ReadFloatTRMMRTGrid(file, precipGrid); + break; + //case PRECIP_TRMMV7: + // precipGrid = ReadFloatTRMMV6Grid(file); + break; + default: + ERROR_LOG("Unsupported precip format!"); + } + + + if (!precipGrid) { + // The precip file was not found! We return zeros if there is no qpf. + if (!hasQPF) { + for (size_t i = 0; i < nodes->size(); i++) { + currentPrecip->at(i) = 0; + } + } + return false; + } + + if (hasQPF) { + // Update this here so we recheck for missing files & don't recheck for forecast precip + strcpy(lastPrecipFile, file); + } + + // We have two options now... Either the precip grid & the basic grids are the same + // Or they are different! + + if (g_DEM->IsSpatialMatch(precipGrid)) { + // The grids are the same! Our life is easy! + #pragma omp parallel for + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (precipGrid->data[node->y][node->x] != precipGrid->noData && precipGrid->data[node->y][node->x] > 0.0) { + currentPrecip->at(i) = precipGrid->data[node->y][node->x] * precipConvert; + } else { + currentPrecip->at(i) = 0; + } + } + + } else { + // The grids are different, we must do some resampling fun. + GridLoc pt; + #pragma omp parallel for + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (precipGrid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && precipGrid->data[pt.y][pt.x] != precipGrid->noData && precipGrid->data[pt.y][pt.x] > 0.0) { + currentPrecip->at(i) = precipGrid->data[pt.y][pt.x] * precipConvert; + } else { + currentPrecip->at(i) = 0; + } + } + + } + + delete precipGrid; + + return true; +} diff --git a/src/PrecipReader.h b/src/PrecipReader.h new file mode 100755 index 0000000..853d7a3 --- /dev/null +++ b/src/PrecipReader.h @@ -0,0 +1,18 @@ +#ifndef PRECIP_READER_H +#define PRECIP_READER_H + +#include <vector> +#include "Defines.h" +#include "BasicGrids.h" +#include "PrecipType.h" + +class PrecipReader { + public: + bool Read(char *file, SUPPORTED_PRECIP_TYPES type, std::vector<GridNode> *nodes, std::vector<float> *currentPrecip, float precipConvert, std::vector<float> *prevPrecip = NULL, bool hasQPF = false); + + private: + char lastPrecipFile[CONFIG_MAX_LEN*2]; + +}; + +#endif diff --git a/src/PrecipType.cpp b/src/PrecipType.cpp new file mode 100755 index 0000000..43cacb8 --- /dev/null +++ b/src/PrecipType.cpp @@ -0,0 +1,39 @@ +#include <cstring> +#include "PrecipType.h" + +const char *precipTypeStrings[] = { + "asc", + "mrms", + "trmmrt", + "trmmv7", + "bif", + "tif", +}; + +SUPPORTED_PRECIP_TYPES PrecipType::GetType() { + return type; +} + +SUPPORTED_PRECIP_TYPES PrecipType::ParseType(char *typeStr) { + SUPPORTED_PRECIP_TYPES result = PRECIP_TYPE_QTY; + + for (int i = 0; i < PRECIP_TYPE_QTY; i++) { + if (!strcasecmp(precipTypeStrings[i], typeStr)) { + result = (SUPPORTED_PRECIP_TYPES)i; + break; + } + } + + type = result; + + return result; + +} + +const char *PrecipType::GetTypes() { + return "ASC, MRMS, TRMMRT, TRMMV7, BIF, TIF"; +} + + + + diff --git a/src/PrecipType.h b/src/PrecipType.h new file mode 100755 index 0000000..885114a --- /dev/null +++ b/src/PrecipType.h @@ -0,0 +1,28 @@ +#ifndef PRECIP_TYPE_H +#define PRECIP_TYPE_H + +enum SUPPORTED_PRECIP_TYPES { + PRECIP_ASCII, + PRECIP_MRMS, + PRECIP_TRMMRT, + PRECIP_TRMMV7, + PRECIP_BIF, + PRECIP_TIF, + PRECIP_TYPE_QTY, +}; + +extern const char *precipTypeStrings[]; + +class PrecipType { + +public: + SUPPORTED_PRECIP_TYPES GetType(); + SUPPORTED_PRECIP_TYPES ParseType(char *typeStr); + const char *GetTypes(); + + +private: + SUPPORTED_PRECIP_TYPES type; +}; + +#endif diff --git a/src/Projection.h b/src/Projection.h new file mode 100755 index 0000000..ba9d1c2 --- /dev/null +++ b/src/Projection.h @@ -0,0 +1,19 @@ +#ifndef PROJECTION_H +#define PROJECTION_H + +enum PROJECTIONS { + PROJECTION_GEOGRAPHIC, + PROJECTION_LAEA, +}; + +class Projection { + + public: + virtual float GetLen(float x, float y, FLOW_DIR dir) = 0; + virtual float GetArea(float x, float y) = 0; + virtual void SetCellSize(float newCellSize) = 0; + virtual void ReprojectPoint(float lon, float lat, float *x, float *y) = 0; + virtual void UnprojectPoint(float x, float y, float *lon, float *lat) = 0; +}; + +#endif diff --git a/src/RPSkewness.cpp b/src/RPSkewness.cpp new file mode 100755 index 0000000..8fa5bd0 --- /dev/null +++ b/src/RPSkewness.cpp @@ -0,0 +1,790 @@ +#include <cmath> +#include <cstdio> +#include "AscGrid.h" +#include "GridWriter.h" +#include "BasicGrids.h" +#include "RPSkewness.h" + +float cs[] = { + -3.0, + -2.9, + -2.8, + -2.7, + -2.6, + -2.5, + -2.4, + -2.3, + -2.2, + -2.1, + -2.0, + -1.9, + -1.8, + -1.7, + -1.6, + -1.5, + -1.4, + -1.3, + -1.2, + -1.1, + -1.0, + -0.9, + -0.8, + -0.7, + -0.6, + -0.5, + -0.4, + -0.3, + -0.2, + -0.1, + 0.0, + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + 0.8, + 0.9, + 1.0, + 1.1, + 1.2, + 1.3, + 1.4, + 1.5, + 1.6, + 1.7, + 1.8, + 1.9, + 2.0, + 2.1, + 2.2, + 2.3, + 2.4, + 2.5, + 2.6, + 2.7, + 2.8, + 2.9, + 3.0, +}; + +float lut1[] = { + -4.051, + -4.013, + -3.973, + -3.932, + -3.899, + -3.845, + -3.8, + -3.753, + -3.705, + -3.656, + -3.605, + -3.553, + -3.499, + -3.444, + -3.88, + -3.33, + -3.271, + -3.211, + -3.149, + -3.087, + -3.022, + -2.957, + -2.891, + -2.824, + -2.755, + -2.686, + -2.615, + -2.544, + -2.472, + -2.4, + -2.326, + -2.252, + -2.178, + -2.104, + -2.029, + -1.955, + -1.88, + -1.806, + -1.733, + -1.66, + -1.588, + -1.518, + -1.449, + -1.383, + -1.256, + -1.197, + -1.14, + -1.087, + -1.037, + -0.99, + -0.946, + -0.905, + -0.867, + -0.832, + -0.799, + -0.769, + -0.74, + -0.714, + -0.69, + -0.667, +}; + +float lut2[] = { + 0.396, + 0.39, + 0.384, + 0.376, + 0.368, + 0.36, + 0.351, + 0.341, + 0.33, + 0.319, + 0.307, + 0.294, + 0.282, + 0.268, + 0.254, + 0.24, + 0.225, + 0.21, + 0.195, + 0.18, + 0.164, + 0.148, + 0.132, + 0.116, + 0.099, + 0.083, + 0.066, + 0.05, + 0.033, + 0.017, + 0.0, + -0.017, + -0.033, + -0.05, + -0.066, + -0.083, + -0.099, + -0.116, + -0.132, + -0.148, + -0.164, + -0.18, + -0.195, + -0.21, + -0.225, + -0.24, + -0.254, + -0.268, + -0.282, + -0.294, + -0.307, + -0.319, + -0.33, + -0.341, + -0.351, + -0.36, + -0.368, + -0.376, + -0.384, + -0.39, + -0.396, +}; + +float lut5[] = { + 0.636, + 0.651, + 0.666, + 0.681, + 0.696, + 0.711, + 0.725, + 0.739, + 0.752, + 0.765, + 0.777, + 0.788, + 0.799, + 0.808, + 0.817, + 0.825, + 0.832, + 0.838, + 0.844, + 0.848, + 0.852, + 0.854, + 0.856, + 0.857, + 0.857, + 0.856, + 0.855, + 0.853, + 0.85, + 0.846, + 0.842, + 0.836, + 0.83, + 0.824, + 0.816, + 0.808, + 0.8, + 0.79, + 0.78, + 0.769, + 0.758, + 0.745, + 0.732, + 0.719, + 0.705, + 0.69, + 0.675, + 0.66, + 0.643, + 0.627, + 0.609, + 0.592, + 0.574, + 0.555, + 0.537, + 0.518, + 0.499, + 0.479, + 0.46, + 0.44, + 0.42, +}; + +float lut10[] = { + 0.66, + 0.681, + 0.702, + 0.724, + 0.747, + 0.711, + 0.795, + 0.819, + 0.844, + 0.869, + 0.895, + 0.92, + 0.945, + 0.97, + 0.994, + 1.018, + 1.041, + 1.064, + 1.086, + 1.107, + 1.128, + 1.147, + 1.166, + 1.183, + 1.2, + 1.216, + 1.231, + 1.245, + 1.258, + 1.27, + 1.282, + 1.292, + 1.301, + 1.309, + 1.317, + 1.323, + 1.328, + 1.333, + 1.336, + 1.339, + 1.34, + 1.341, + 1.34, + 1.339, + 1.337, + 1.333, + 1.329, + 1.324, + 1.318, + 1.31, + 1.302, + 1.294, + 1.284, + 1.274, + 1.262, + 1.25, + 1.238, + 1.224, + 1.21, + 1.195, + 1.18, +}; + +float lut25[] = { + 0.666, + 0.683, + 0.712, + 0.738, + 0.764, + 0.793, + 0.823, + 0.855, + 0.888, + 0.923, + 0.959, + 0.996, + 1.035, + 1.075, + 1.116, + 1.157, + 1.198, + 1.24, + 1.282, + 1.324, + 1.366, + 1.407, + 1.448, + 1.488, + 1.528, + 1.567, + 1.606, + 1.643, + 1.68, + 1.716, + 1.751, + 1.785, + 1.818, + 1.849, + 1.88, + 1.91, + 1.939, + 1.967, + 1.993, + 2.018, + 2.043, + 2.066, + 2.087, + 2.108, + 2.128, + 2.146, + 2.163, + 2.179, + 2.193, + 2.207, + 2.219, + 2.23, + 2.24, + 2.248, + 2.256, + 2.262, + 2.267, + 2.272, + 2.275, + 2.277, + 2.278, +}; + +float lut50[] = { + 0.666, + 0.689, + 0.714, + 0.74, + 0.768, + 0.798, + 0.83, + 0.864, + 0.9, + 0.939, + 0.98, + 1.023, + 1.069, + 1.116, + 1.166, + 1.217, + 1.27, + 1.324, + 1.379, + 1.435, + 1.492, + 1.549, + 1.606, + 1.663, + 1.72, + 1.777, + 1.834, + 1.89, + 1.945, + 2, + 2.054, + 2.107, + 2.159, + 2.211, + 2.261, + 2.311, + 2.359, + 2.407, + 2.453, + 2.498, + 2.542, + 2.585, + 2.626, + 2.666, + 2.706, + 2.743, + 2.78, + 2.815, + 2.848, + 2.881, + 2.912, + 2.942, + 2.97, + 2.997, + 3.023, + 3.048, + 3.071, + 3.093, + 3.114, + 3.134, + 3.152, +}; + +float lut100[] = { + 0.667, + 0.69, + 0.714, + 0.74, + 0.769, + 0.799, + 0.832, + 0.867, + 0.905, + 0.946, + 0.99, + 1.037, + 1.087, + 1.14, + 1.197, + 1.256, + 1.318, + 1.383, + 1.449, + 1.518, + 1.588, + 1.66, + 1.733, + 1.806, + 1.88, + 1.955, + 2.029, + 2.104, + 2.178, + 2.252, + 2.326, + 2.4, + 2.472, + 2.544, + 2.615, + 2.686, + 2.755, + 2.824, + 2.891, + 2.957, + 3.022, + 3.087, + 3.149, + 3.211, + 3.271, + 3.33, + 3.388, + 3.444, + 3.499, + 3.553, + 3.605, + 3.656, + 3.705, + 3.753, + 3.8, + 3.845, + 3.889, + 3.932, + 3.973, + 4.013, + 4.051, +}; + +float lut200[] = { + 0.667, + 0.69, + 0.714, + 0.741, + 0.769, + 0.8, + 0.833, + 0.869, + 0.907, + 0.949, + 0.995, + 1.044, + 1.097, + 1.155, + 1.216, + 1.282, + 1.351, + 1.424, + 1.501, + 1.581, + 1.664, + 1.749, + 1.837, + 1.926, + 2.016, + 2.108, + 2.201, + 2.294, + 2.388, + 2.482, + 2.576, + 2.67, + 2.763, + 2.856, + 2.949, + 3.041, + 3.132, + 3.223, + 3.312, + 3.401, + 3.489, + 3.575, + 3.661, + 3.745, + 3.828, + 3.91, + 3.99, + 4.069, + 4.147, + 4.223, + 4.298, + 4.372, + 4.444, + 4.515, + 4.584, + 4.652, + 4.718, + 4.783, + 4.847, + 4.904, + 4.97, +}; + +bool ReadLP3File(char *file, std::vector<GridNode> *nodes, std::vector<float> *lp3Vals) { + FloatGrid *grid = NULL; + + grid = ReadFloatTifGrid(file); + + if (!grid) { + return false; + } + + // We have two options now... Either the grid & the basic grids are the same + // Or they are different! + + if (true) {//g_DEM->IsSpatialMatch(grid)) { + printf("Loading exact match LP3 grid %s\n", file); + // The grids are the same! Our life is easy! + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (grid->data[node->y][node->x] != grid->noData) { + lp3Vals->at(i) = grid->data[node->y][node->x]; + } else { + lp3Vals->at(i) = 0; + } + } + + } else { + printf("LP3 grids aren't an exact match so guessing! %s\n", file); + // The grids are different, we must do some resampling fun. + GridLoc pt; + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && grid->data[pt.y][pt.x] != grid->noData) { + lp3Vals->at(i) = grid->data[pt.y][pt.x]; + } else { + lp3Vals->at(i) = 0; + } + } + + } + + delete grid; + + return true; +} + +void CalcLP3Vals(std::vector<float> *stdGrid, std::vector<float> *avgGrid, std::vector<float> *scGrid, std::vector<RPData> *rpData, std::vector<GridNode> *nodes) { + std::vector<float> count2; + count2.resize(rpData->size()); + for (size_t i = 0; i < rpData->size(); i++) { + int index = (int)(scGrid->at(i) * 10.0 + 30.0); + if (index < 0) { + index = 0; + /*rpData->at(i).q1 = -1; + rpData->at(i).q2 = -1; + rpData->at(i).q5 = -1; + rpData->at(i).q10 = -1; + rpData->at(i).q25 = -1; + rpData->at(i).q50 = -1; + rpData->at(i).q100 = -1; + rpData->at(i).q200 = -1; + continue;*/ + } else if (index >= 60) { + index = 59; + } + + // 1 + float diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + float diff_q = lut1[index + 1] - lut1[index]; + float lerp = lut1[index] + diff_cs * diff_q; + float std = stdGrid->at(i); + float avg = avgGrid->at(i); + rpData->at(i).q1 = powf(10.0, avg + lerp * std); + // 2 + diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + diff_q = lut2[index + 1] - lut2[index]; + lerp = lut2[index] + diff_cs * diff_q; + rpData->at(i).q2 = powf(10.0, avg + lerp * std); + count2[i] = rpData->at(i).q2; + // 5 + diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + diff_q = lut5[index + 1] - lut5[index]; + lerp = lut5[index] + diff_cs * diff_q; + rpData->at(i).q5 = powf(10.0, avg + lerp * std); + // 10 + diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + diff_q = lut10[index + 1] - lut10[index]; + lerp = lut10[index] + diff_cs * diff_q; + rpData->at(i).q10 = powf(10.0, avg + lerp * std); + // 25 + diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + diff_q = lut25[index + 1] - lut25[index]; + lerp = lut25[index] + diff_cs * diff_q; + rpData->at(i).q25 = powf(10.0, avg + lerp * std); + // 50 + diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + diff_q = lut50[index + 1] - lut50[index]; + lerp = lut50[index] + diff_cs * diff_q; + rpData->at(i).q50 = powf(10.0, avg + lerp * std); + // 100 + diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + diff_q = lut100[index + 1] - lut100[index]; + lerp = lut100[index] + diff_cs * diff_q; + rpData->at(i).q100 = powf(10.0, avg + lerp * std); + // 200 + diff_cs = (scGrid->at(i) - cs[index]) / (cs[index + 1] - cs[index]); + diff_q = lut200[index + 1] - lut200[index]; + lerp = lut200[index] + diff_cs * diff_q; + rpData->at(i).q200 = powf(10.0, avg + lerp * std); + } + //GridWriter gridWriter; + //gridWriter.Initialize(nodes); + //gridWriter.WriteGrid(nodes, &count2, "2qflow.asc"); +} +#ifdef LOGNORMAL +void CalcLP3Vals(std::vector<float> *stdGrid, std::vector<float> *avgGrid, std::vector<float> *scGrid, std::vector<RPData> *rpData, std::vector<GridNode> *nodes) { + std::vector<float> count2; + count2.resize(rpData->size()); + for (size_t i = 0; i < rpData->size(); i++) { + + float lerp = -2.326; + rpData->at(i).q1 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + // 2 + lerp = 0.000; + rpData->at(i).q2 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + count2[i] = rpData->at(i).q2; + // 5 + lerp = 0.842; + rpData->at(i).q5 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + // 10 + lerp = 1.282; + rpData->at(i).q10 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + // 25 + lerp = 1.751; + rpData->at(i).q25 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + // 50 + lerp = 2.054; + rpData->at(i).q50 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + // 100 + lerp = 2.326; + rpData->at(i).q100 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + // 200 + lerp = 2.576; + rpData->at(i).q200 = powf(10.0, avgGrid->at(i) + lerp * stdGrid->at(i)); + } + GridWriter gridWriter; + gridWriter.Initialize(nodes); + gridWriter.WriteGrid(nodes, &count2, "2qflow.asc"); +} +#endif +float GetReturnPeriod(float q, RPData *rpData) { + if (rpData->q1 == -1) { + return -1; + } + + if (q > rpData->q200) { + return 200; // No Extrapolation... + } + + float diff_q, diff_rp; + + if (q > rpData->q100) { + diff_q = (q - rpData->q100) / (rpData->q200 - rpData->q100); + diff_rp = 200.0 - 100.0; + return 100.0 + diff_q * diff_rp; + } + + if (q > rpData->q50) { + diff_q = (q - rpData->q50) / (rpData->q100 - rpData->q50); + diff_rp = 100.0 - 50.0; + return 50.0 + diff_q * diff_rp; + } + + if (q > rpData->q25) { + diff_q = (q - rpData->q25) / (rpData->q50 - rpData->q25); + diff_rp = 50.0 - 25.0; + return 25.0 + diff_q * diff_rp; + } + + if (q > rpData->q10) { + diff_q = (q - rpData->q10) / (rpData->q25 - rpData->q10); + diff_rp = 25.0 - 10.0; + return 10.0 + diff_q * diff_rp; + } + + if (q > rpData->q5) { + diff_q = (q - rpData->q5) / (rpData->q10 - rpData->q5); + diff_rp = 10.0 - 5.0; + return 5.0 + diff_q * diff_rp; + } + + if (q > rpData->q2) { + diff_q = (q - rpData->q2) / (rpData->q5 - rpData->q2); + diff_rp = 5.0 - 2.0; + return 2.0 + diff_q * diff_rp; + } + + if (q > rpData->q1) { + diff_q = (q - rpData->q1) / (rpData->q2 - rpData->q1); + diff_rp = 2.0 - 1.0; + float retVal = 1.0 + diff_q * diff_rp; + if (retVal >= 2.0) { + retVal = 1.99; + } + return retVal; + } + + return 0; +} + diff --git a/src/RPSkewness.h b/src/RPSkewness.h new file mode 100755 index 0000000..e24d3f2 --- /dev/null +++ b/src/RPSkewness.h @@ -0,0 +1,22 @@ +#ifndef RPSKEWNESS_H +#define RPSKEWNESS_H + +#include <vector> +#include "GridNode.h" + +struct RPData { + float q1; + float q2; + float q5; + float q10; + float q25; + float q50; + float q100; + float q200; +}; + +bool ReadLP3File(char *file, std::vector<GridNode> *nodes, std::vector<float> *lp3Vals); +void CalcLP3Vals(std::vector<float> *stdGrid, std::vector<float> *avgGrid, std::vector<float> *scGrid, std::vector<RPData> *rpData, std::vector<GridNode> *nodes); +float GetReturnPeriod(float q, RPData *rpData); + +#endif diff --git a/src/RoutingCaliParamConfigSection.cpp b/src/RoutingCaliParamConfigSection.cpp new file mode 100755 index 0000000..295d5dd --- /dev/null +++ b/src/RoutingCaliParamConfigSection.cpp @@ -0,0 +1,111 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "RoutingCaliParamConfigSection.h" + +std::map<std::string, RoutingCaliParamConfigSection *> g_routingCaliParamConfigs[ROUTE_QTY]; + +RoutingCaliParamConfigSection::RoutingCaliParamConfigSection(char *nameVal, ROUTES routeVal) { + strcpy(name, nameVal); + gauge = NULL; + route = routeVal; + int numParams = numRouteParams[route]; + modelParamMins = new float[numParams]; + modelParamMaxs = new float[numParams]; + modelParamInits = new float[numParams]; + paramsSet = new bool[numParams]; + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamInits, 0, sizeof(float)*numParams); + memset(paramsSet, 0, sizeof(bool)*numParams); + +} + +RoutingCaliParamConfigSection::~RoutingCaliParamConfigSection() { + delete [] modelParamMins; + delete [] modelParamMaxs; + delete [] modelParamInits; +} + +char *RoutingCaliParamConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET RoutingCaliParamConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numRouteParams[route]; + + if (!strcasecmp(name, "gauge")) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + gauge = itr->second; + } else { + if (!gauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + //Lets see if this belongs to a parameter + for (int i = 0; i < numParams; i++) { + if (strcasecmp(name, routeParamStrings[route][i]) == 0) { + + if (paramsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + float minVal = 0, maxVal = 0, initVal = 0; + int count = sscanf(value, "%f,%f,%f", &minVal, &maxVal, &initVal); + + if (count < 2) { + ERROR_LOGF("Parameter \"%s\" has invalid calibration values!", name); + return INVALID_RESULT; + } + + modelParamMins[i] = minVal; + modelParamMaxs[i] = maxVal; + modelParamInits[i] = initVal; + paramsSet[i] = true; + + return VALID_RESULT; + } + } + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET RoutingCaliParamConfigSection::ValidateSection() { + int numParams = numRouteParams[route]; + + if (!gauge) { + ERROR_LOG("The gauge on which calibration is to be performed was not set!"); + return INVALID_RESULT; + } + + for (int i = 0; i < numParams; i++) { + if (!paramsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", routeParamStrings[route][i]); + return INVALID_RESULT; + } + } + + return VALID_RESULT; +} + +bool RoutingCaliParamConfigSection::IsDuplicate(char *name, ROUTES routeVal) { + std::map<std::string, RoutingCaliParamConfigSection *>::iterator itr = g_routingCaliParamConfigs[routeVal].find(name); + if (itr == g_routingCaliParamConfigs[routeVal].end()) { + return false; + } else { + return true; + } +} diff --git a/src/RoutingCaliParamConfigSection.h b/src/RoutingCaliParamConfigSection.h new file mode 100755 index 0000000..a6c5ac4 --- /dev/null +++ b/src/RoutingCaliParamConfigSection.h @@ -0,0 +1,40 @@ +#ifndef CONFIG_ROUTINGCALIPARAM_SECTION_H +#define CONFIG_ROUTINGCALIPARAM_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" +#include "ObjectiveFunc.h" + +class RoutingCaliParamConfigSection : public ConfigSection { + + public: + RoutingCaliParamConfigSection(char *nameVal, ROUTES routeVal); + ~RoutingCaliParamConfigSection(); + + GaugeConfigSection *GetGauge() { return gauge; } + float *GetParamMins() { return modelParamMins; } + float *GetParamMaxs() { return modelParamMaxs; } + float *GetParamInits() { return modelParamInits; } + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name, ROUTES routeVal); + + private: + char name[CONFIG_MAX_LEN]; + ROUTES route; + GaugeConfigSection *gauge; + float *modelParamMins; + float *modelParamMaxs; + float *modelParamInits; + bool *paramsSet; +}; + +extern std::map<std::string, RoutingCaliParamConfigSection *> g_routingCaliParamConfigs[]; + +#endif diff --git a/src/RoutingParamSetConfigSection.cpp b/src/RoutingParamSetConfigSection.cpp new file mode 100755 index 0000000..7b5f517 --- /dev/null +++ b/src/RoutingParamSetConfigSection.cpp @@ -0,0 +1,135 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "RoutingParamSetConfigSection.h" + +std::map<std::string, RoutingParamSetConfigSection *> g_routingParamSetConfigs[ROUTE_QTY]; + +RoutingParamSetConfigSection::RoutingParamSetConfigSection(char *nameVal, ROUTES routeVal) { + strcpy(name, nameVal); + currentGauge = NULL; + currentParams = NULL; + currentParamsSet = NULL; + route = routeVal; + paramGrids.resize(numRouteParams[route]); +} + +RoutingParamSetConfigSection::~RoutingParamSetConfigSection() { + +} + +char *RoutingParamSetConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET RoutingParamSetConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numRouteParams[route]; + + if (strcasecmp(name, "gauge") == 0) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", routeParamStrings[route][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + if (IsDuplicateGauge(itr->second)) { + ERROR_LOGF("Duplicate gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + currentGauge = itr->second; + currentParams = new float[numParams]; + currentParamsSet = new bool[numParams]; + memset(currentParams, 0, sizeof(float)*numParams); + memset(currentParamsSet, 0, sizeof(bool)*numParams); + } else { + // Lets see if this belongs to a parameter grid + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, routeParamGridStrings[route][i]) == 0) { + paramGrids[i] = std::string(value); + return VALID_RESULT; + } + } + + + if (!currentGauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + //Lets see if this belongs to a parameter scalar + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, routeParamStrings[route][i]) == 0) { + + if (currentParamsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + currentParams[i] = atof(value); + currentParamsSet[i] = true; + + return VALID_RESULT; + } + } + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET RoutingParamSetConfigSection::ValidateSection() { + int numParams = numRouteParams[route]; + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", routeParamStrings[route][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + + + return VALID_RESULT; +} + +bool RoutingParamSetConfigSection::IsDuplicate(char *name, ROUTES routeVal) { + std::map<std::string, RoutingParamSetConfigSection *>::iterator itr = g_routingParamSetConfigs[routeVal].find(name); + if (itr == g_routingParamSetConfigs[routeVal].end()) { + return false; + } else { + return true; + } +} + +bool RoutingParamSetConfigSection::IsDuplicateGauge(GaugeConfigSection *gaugeVal) { + std::map<GaugeConfigSection *, float *>::iterator itr = paramSettings.find(gaugeVal); + if (itr == paramSettings.end()) { + return false; + } else { + return true; + } +} diff --git a/src/RoutingParamSetConfigSection.h b/src/RoutingParamSetConfigSection.h new file mode 100755 index 0000000..9503046 --- /dev/null +++ b/src/RoutingParamSetConfigSection.h @@ -0,0 +1,40 @@ +#ifndef CONFIG_ROUTINGPARAMSET_SECTION_H +#define CONFIG_ROUTINGPARAMSET_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" + +class RoutingParamSetConfigSection : public ConfigSection { + + public: + RoutingParamSetConfigSection(char *nameVal, ROUTES routeVal); + ~RoutingParamSetConfigSection(); + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + std::map<GaugeConfigSection *, float *> *GetParamSettings() { return ¶mSettings; } + std::vector<std::string> *GetParamGrids() { return ¶mGrids; } + + static bool IsDuplicate(char *name, ROUTES routeVal); + + private: + bool IsDuplicateGauge(GaugeConfigSection *); + + char name[CONFIG_MAX_LEN]; + ROUTES route; + GaugeConfigSection *currentGauge; + float *currentParams; + bool *currentParamsSet; + std::map<GaugeConfigSection *, float *> paramSettings; + std::vector<std::string> paramGrids; + + +}; + +extern std::map<std::string, RoutingParamSetConfigSection *> g_routingParamSetConfigs[]; + +#endif diff --git a/src/SAC.cpp b/src/SAC.cpp new file mode 100755 index 0000000..0410b23 --- /dev/null +++ b/src/SAC.cpp @@ -0,0 +1,647 @@ +#include <cmath> +#include <cstdio> +#include <cstring> +#include "DatedName.h" +#include "SAC.h" + +SAC::SAC() { +} + +SAC::~SAC() { + +} + +bool SAC::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (sacNodes.size() != nodes->size()) { + sacNodes.resize(nodes->size()); + } + + // Fill in modelNode in the gridNodes + std::vector<SACGridNode>::iterator citr = sacNodes.begin(); + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + SACGridNode *cNode = &(*citr); + + node->modelNode = cNode; + + citr++; + } + + + InitializeParameters(paramSettings, paramGrids); + + return true; +} + +void SAC::InitializeStates(TimeVar *beginTime, char *statePath) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(beginTime->GetTM()); + + char buffer[255]; + sprintf(buffer, "%s/uztwc_%s.tif", statePath, timeStr.GetName()); + FloatGrid *smGrid = ReadFloatTifGrid(buffer); + if (smGrid) { + if (g_DEM->IsSpatialMatch(smGrid)) { + printf("Using Previous UZTWC Grid %s\n", buffer); + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + SACGridNode *cNode = &(sacNodes[i]); + if (smGrid->data[node->y][node->x] != smGrid->noData) { + cNode->UZTWC = smGrid->data[node->y][node->x]; + } + } + } else { + printf("Previous UZTWC Grid %s not a spatial match!\n", buffer); + } + delete smGrid; + } else { + printf("Previous UZTWC Grid %s not found!\n", buffer); + } + + sprintf(buffer, "%s/uzfwc_%s.tif", statePath, timeStr.GetName()); + smGrid = ReadFloatTifGrid(buffer); + if (smGrid) { + if (g_DEM->IsSpatialMatch(smGrid)) { + printf("Using Previous UZFWC Grid %s\n", buffer); + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + SACGridNode *cNode = &(sacNodes[i]); + if (smGrid->data[node->y][node->x] != smGrid->noData) { + cNode->UZFWC = smGrid->data[node->y][node->x]; + } + } + } else { + printf("Previous UZFWC Grid %s not a spatial match!\n", buffer); + } + delete smGrid; + } else { + printf("Previous UZFWC Grid %s not found!\n", buffer); + } + + sprintf(buffer, "%s/lztwc_%s.tif", statePath, timeStr.GetName()); + smGrid = ReadFloatTifGrid(buffer); + if (smGrid) { + if (g_DEM->IsSpatialMatch(smGrid)) { + printf("Using Previous LZTWC Grid %s\n", buffer); + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + SACGridNode *cNode = &(sacNodes[i]); + if (smGrid->data[node->y][node->x] != smGrid->noData) { + cNode->LZTWC = smGrid->data[node->y][node->x]; + } + } + } else { + printf("Previous LZTWC Grid %s not a spatial match!\n", buffer); + } + delete smGrid; + } else { + printf("Previous LZTWC Grid %s not found!\n", buffer); + } + + sprintf(buffer, "%s/lzfsc_%s.tif", statePath, timeStr.GetName()); + smGrid = ReadFloatTifGrid(buffer); + if (smGrid) { + if (g_DEM->IsSpatialMatch(smGrid)) { + printf("Using Previous LZFSC Grid %s\n", buffer); + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + SACGridNode *cNode = &(sacNodes[i]); + if (smGrid->data[node->y][node->x] != smGrid->noData) { + cNode->LZFSC = smGrid->data[node->y][node->x]; + } + } + } else { + printf("Previous LZFSC Grid %s not a spatial match!\n", buffer); + } + delete smGrid; + } else { + printf("Previous LZFSC Grid %s not found!\n", buffer); + } + + sprintf(buffer, "%s/lzfpc_%s.tif", statePath, timeStr.GetName()); + smGrid = ReadFloatTifGrid(buffer); + if (smGrid) { + if (g_DEM->IsSpatialMatch(smGrid)) { + printf("Using Previous LZFPC Grid %s\n", buffer); + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + SACGridNode *cNode = &(sacNodes[i]); + if (smGrid->data[node->y][node->x] != smGrid->noData) { + cNode->LZFPC = smGrid->data[node->y][node->x]; + } + } + } else { + printf("Previous LZFPC Grid %s not a spatial match!\n", buffer); + } + delete smGrid; + } else { + printf("Previous LZFPC Grid %s not found!\n", buffer); + } + + sprintf(buffer, "%s/adimc_%s.tif", statePath, timeStr.GetName()); + smGrid = ReadFloatTifGrid(buffer); + if (smGrid) { + if (g_DEM->IsSpatialMatch(smGrid)) { + printf("Using Previous ADIMC Grid %s\n", buffer); + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + SACGridNode *cNode = &(sacNodes[i]); + if (smGrid->data[node->y][node->x] != smGrid->noData) { + cNode->ADIMC = smGrid->data[node->y][node->x]; + } + } + } else { + printf("Previous ADIMC Grid %s not a spatial match!\n", buffer); + } + delete smGrid; + } else { + printf("Previous ADIMC Grid %s not found!\n", buffer); + } +} + +void SAC::SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(currentTime->GetTM()); + + std::vector<float> dataVals; + dataVals.resize(nodes->size()); + + //UZTWC, UZFWC, LZTWC, LZFSC, LZFPC, ADIMC + + char buffer[255]; + sprintf(buffer, "%s/uztwc_%s.tif", statePath, timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + SACGridNode *cNode = &(sacNodes[i]); + dataVals[i] = cNode->UZTWC; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + + sprintf(buffer, "%s/uzfwc_%s.tif", statePath, timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + SACGridNode *cNode = &(sacNodes[i]); + dataVals[i] = cNode->UZFWC; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + + sprintf(buffer, "%s/lztwc_%s.tif", statePath, timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + SACGridNode *cNode = &(sacNodes[i]); + dataVals[i] = cNode->LZTWC; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + + sprintf(buffer, "%s/lzfsc_%s.tif", statePath, timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + SACGridNode *cNode = &(sacNodes[i]); + dataVals[i] = cNode->LZFSC; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + + sprintf(buffer, "%s/lzfpc_%s.tif", statePath, timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + SACGridNode *cNode = &(sacNodes[i]); + dataVals[i] = cNode->LZFPC; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + + sprintf(buffer, "%s/adimc_%s.tif", statePath, timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + SACGridNode *cNode = &(sacNodes[i]); + dataVals[i] = cNode->ADIMC; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + +} +bool SAC::WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture) { + + size_t numNodes = nodes->size(); + size_t i = 0; + +#if _OPENMP + #pragma omp parallel for +#endif + for (i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + if (!node->gauge) { + continue; + } + SACGridNode *cNode = (SACGridNode*)node->modelNode; + WaterBalanceInt(node, cNode, stepHours, precip->at(i), pet->at(i)); + fastFlow->at(i) += (cNode->dischargeF / (stepHours * 3600.0f)); + slowFlow->at(i) += (cNode->dischargeS / (stepHours * 3600.0f)); + soilMoisture->at(i) = 100.0 * (cNode->UZTWC + cNode->UZFWC) / (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_UZFWM]); + if (!std::isfinite(soilMoisture->at(i))) { + soilMoisture->at(i) = 0; + } + //soilMoisture->at(i) = (cNode->UZTWC + cNode->UZFWC) / (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_UZFWM]); + //discharge->at(i) = (cNode->dischargeF + cNode->dischargeS) * node->area * 0.277777777777778f; // Convert from mm/time to cms; + //printf(" Q %f\n", discharge->at(i)); + //LocalRouteQF(node, cNode); + //LocalRouteSF(node, cNode); + } + + return true; +} + +void SAC::WaterBalanceInt(GridNode *node, SACGridNode *cNode, float stepHours, float precipIn, float petIn) { + + /*float precip = 0.0f; //precipIn * stepHours; // precipIn is mm/hr, precip is mm + float pet = 20.0f; //petIn * stepHours; // petIn in mm/hr, pet is mm + float DT = 3.0f / 24.0f; //stepHours / 24.0f;*/ + + + float precip = precipIn * stepHours; //stepHours; //stepHours; // precipIn is mm/hr, precip is mm + float pet = petIn * stepHours;// * 0.06; // petIn in mm/hr, pet is mm + float DT = stepHours / 24.0f; + + float PAREA = 1.0f - cNode->params[PARAM_SAC_PCTIM] - cNode->params[PARAM_SAC_ADIMP]; + + /*******************************/ + /* ET Calculations */ + /*******************************/ + + float E1 = 0.0f; // ET from upper zone + float RED = 0.0f; // Residual ET demand + float E2 = 0.0f; // ET from UZFWC + float E3 = 0.0f; // ET from lower zone (LZTWC) + float E5 = 0.0f; // ET from ADIMP area + + E1 = pet * (cNode->UZTWC / cNode->params[PARAM_SAC_UZTWM]); // ET from upper zone + RED = pet - E1; // Residual ET demand + cNode->UZTWC -= E1; + if (cNode->UZTWC < 0.0f) { // E1 can't exceed UZTWC + E1 += cNode->UZTWC; + cNode->UZTWC = 0.0f; + RED = pet - E1; + if (cNode->UZFWC < RED) { + E2 = cNode->UZFWC; + cNode->UZFWC = 0.0f; + RED = RED - E2; + } else { + E2 = RED; + cNode->UZFWC -= E2; + RED = 0.0f; + } + } + + if ((cNode->UZTWC / cNode->params[PARAM_SAC_UZTWM]) < (cNode->UZFWC / cNode->params[PARAM_SAC_UZFWM])) { + // Upper zone free water ratio exceeds upper zone tension + // water ratio, thus transfer free water to tension + float UZRAT = (cNode->UZTWC + cNode->UZFWC) / (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_UZFWM]); + cNode->UZTWC = cNode->params[PARAM_SAC_UZTWM] * UZRAT; + cNode->UZFWC = cNode->params[PARAM_SAC_UZFWM] * UZRAT; + } + + if (cNode->UZTWC < 0.00001f) { + cNode->UZTWC = 0.0f; + } + + if (cNode->UZFWC < 0.00001f) { + cNode->UZFWC = 0.0f; + } + + E3 = RED * (cNode->LZTWC / (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM])); + cNode->LZTWC -= E3; + + if (cNode->LZTWC < 0.0f) { + // E3 can't exceed LZTWC + E3 += cNode->LZTWC; + cNode->LZTWC = 0.0f; + } + + float RATLZT = cNode->LZTWC / cNode->params[PARAM_SAC_LZTWM]; + float RATLZ = (cNode->LZTWC + cNode->LZFPC + cNode->LZFSC - cNode->params[PARAM_SAC_RSERV]) / (cNode->params[PARAM_SAC_LZTWM] + cNode->params[PARAM_SAC_LZFPM] + cNode->params[PARAM_SAC_LZFSM] - cNode->params[PARAM_SAC_RSERV]); + + if (RATLZT < RATLZ) { + // Resupply lower zone tension water from lower + // zone free water if more water available there. + float DEL = (RATLZ - RATLZT) * cNode->params[PARAM_SAC_LZTWM]; + cNode->LZTWC += DEL; + cNode->LZFSC -= DEL; + if (cNode->LZFSC < 0.0f) { + // If transfer exceeds LZFSC then remainder comes from LZFPC + cNode->LZFPC += cNode->LZFSC; + cNode->LZFSC = 0.0f; + } + } + + if (cNode->LZTWC < 0.00001f) { + cNode->LZTWC = 0.0f; + } + + E5 = E1 + (RED + E2) * ((cNode->ADIMC - E1 - cNode->UZTWC) / (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM])); + // Adjust adimc, additional impervious area storage, for evaporation + cNode->ADIMC -= E5; + + if (cNode->ADIMC < 0.0f) { + E5 += cNode->ADIMC; + cNode->ADIMC = 0.0f; + } + + E5 *= cNode->params[PARAM_SAC_ADIMP]; + + /**********************************************/ + /* Compute Percolation & runoff amounts */ + /**********************************************/ + + // TWX is the time interval available moisture in excess of UZTW requirements + float TWX = precip + cNode->UZTWC - cNode->params[PARAM_SAC_UZTWM]; + + if (TWX < 0.0f) { + // All moisture held in UZTW -- No excess. + cNode->UZTWC += precip; + TWX = 0.0f; + } else { + cNode->UZTWC = cNode->params[PARAM_SAC_UZTWM]; // Moisture in excess of UZTW storage + } + + cNode->ADIMC = cNode->ADIMC + precip - TWX; + + // Compute impervious area runoff + float ROIMP = precip * cNode->params[PARAM_SAC_PCTIM]; // Runoff from minimum impervious area + + float SBF = 0.0f, SSUR = 0.0f, SIF = 0.0f, SPERC = 0.0f, SDRO = 0.0f, SPBF = 0.0f; + + float NINC = floor(1.0f + 0.2f * (cNode->UZFWC + TWX)); // Number of time increments that the time interval is divided into for further soil-moisture accounting. + // No one increment will exceed 5.0 millimeters of UZFWC+PAV + + float DINC = (1.0f / NINC) * DT; // Length of each increment in days + + float PINC = TWX / NINC; // Amount of available moisture for each increment. Compute free water depletion fractions for the time increment + // being used-basic depletions are for one day + + float DUZ = 1.0f - pow(1.0f - cNode->params[PARAM_SAC_UZK], DINC); + float DLZP = 1.0f - pow(1.0f - cNode->params[PARAM_SAC_LZPK], DINC); + float DLZS = 1.0f - pow(1.0f - cNode->params[PARAM_SAC_LZSK], DINC); + + /*******************************************/ + /* Do loop for time interval */ + /*******************************************/ + + for (float i = 0.0f; i < NINC; i = i + 1.0f) { + float ADSUR = 0.0f; + float RATIO = (cNode->ADIMC - cNode->UZTWC) / cNode->params[PARAM_SAC_LZTWM]; + if (RATIO < 0.0f) { + RATIO = 0.0f; + } + + float ADDRO = PINC * pow(RATIO, 2.0f); // Amount of direct runoff from the area ADIMP + + // Compute baseflow + float BF = cNode->LZFPC * DLZP; + cNode->LZFPC -= BF; + if (cNode->LZFPC <= 0.0001f) { + BF += cNode->LZFPC; + cNode->LZFPC = 0.0f; + } + + SBF += BF; + SPBF += BF; + + BF = cNode->LZFSC * DLZS; + cNode->LZFSC -= BF; + if (cNode->LZFSC <= 0.0001f) { + BF += cNode->LZFSC; + cNode->LZFSC = 0.0f; + } + + SBF += BF; + + // Compute Percolation, If no water is available then skip + if ((PINC + cNode->UZFWC) <= 0.01f) { + /*cNode->UZFWC += PINC; + cNode->ADIMC = cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM]; + SDRO = SDRO + ADDRO * cNode->params[PARAM_SAC_ADIMP]; + if (cNode->ADIMC < 0.00001f) { + cNode->ADIMC = 0.0f; + }*/ + + cNode->ADIMC = cNode->ADIMC + PINC - ADDRO - ADSUR; + if (cNode->ADIMC > (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM])) { + ADDRO = ADDRO + cNode->ADIMC - (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM]); + cNode->ADIMC = cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM]; + } + SDRO = SDRO + ADDRO * cNode->params[PARAM_SAC_ADIMP]; + if (cNode->ADIMC < 0.00001f) { + cNode->ADIMC = 0.0f; + } + continue; + } + + float PERCM = cNode->params[PARAM_SAC_LZFPM] * DLZP + cNode->params[PARAM_SAC_LZFSM] * DLZS; + float PERC = PERCM * (cNode->UZFWC / cNode->params[PARAM_SAC_UZFWM]); + // DEFR is the lower zone moisture deficiency ratio + float DEFR = 1.0f - ((cNode->LZTWC + cNode->LZFPC + cNode->LZFSC) / (cNode->params[PARAM_SAC_LZTWM] + cNode->params[PARAM_SAC_LZFPM] + cNode->params[PARAM_SAC_LZFSM])); + float FR = 1.0f; // Change in percolation withdrawal due to frozen ground. + float FI = 1.0f; // Change in interflow withdrawal due to frozen ground. + //float IFRZE = 0.0f; + + PERC = PERC * (1.0f + cNode->params[PARAM_SAC_ZPERC] * pow(DEFR, cNode->params[PARAM_SAC_REXP])) * FR; + // Note... percolation occurs from UZFWC before PAV is added. + + if (PERC >= cNode->UZFWC) { + PERC = cNode->UZFWC; + } + + cNode->UZFWC -= PERC; + + // Check to see if percolation exceeds lower zone deficiency + float CHECK = cNode->LZTWC + cNode->LZFPC + cNode->LZFSC + PERC - cNode->params[PARAM_SAC_LZTWM] - cNode->params[PARAM_SAC_LZFPM] - cNode->params[PARAM_SAC_LZFSM]; + if (CHECK > 0.0f) { + PERC -= CHECK; + cNode->UZFWC += CHECK; + } + + SPERC += PERC; // Time interval summation of PERC + + // Compute interflow and keep track of time interval sum + // Note PINC has not yet been added + float DEL = cNode->UZFWC * DUZ * FI; + SIF += DEL; + cNode->UZFWC -= DEL; + + // Distribute percolated water into the lower zones + // tension water must be filled first except for the PFREE area. + // PERCT is percolation to tension water and PERCF is percolation going to free water + float PERCT = PERC * (1.0f - cNode->params[PARAM_SAC_PFREE]); + float PERCF; + if ((PERCT + cNode->LZTWC) <= cNode->params[PARAM_SAC_LZTWM]) { + cNode->LZTWC += PERCT; + PERCF = 0.0f; + } else { + PERCF = PERCT + cNode->LZTWC - cNode->params[PARAM_SAC_LZTWM]; + cNode->LZTWC = cNode->params[PARAM_SAC_LZTWM]; + } + + // Distribute percolation in excess of tension requirements among the + // free water storages + PERCF += (PERC * cNode->params[PARAM_SAC_PFREE]); + if (PERCF != 0.0f) { + float HPL = cNode->params[PARAM_SAC_LZFPM] / (cNode->params[PARAM_SAC_LZFPM] + cNode->params[PARAM_SAC_LZFSM]); + // HPL is the relative size of the primary storage + // as compared with total lower zone free water storage + + float RATLP = cNode->LZFPC / cNode->params[PARAM_SAC_LZFPM]; + float RATLS = cNode->LZFSC / cNode->params[PARAM_SAC_LZFSM]; + // RATLP and RATLS are content capacit ratios, or in other words + // the relative fullness of each storage + + float FRACP = (HPL * 2.0f * (1.0f - RATLP)) / ((1.0f - RATLP) + (1.0f - RATLS)); + // FRACP is the fraction going to primary + if (FRACP > 1.0f) { + FRACP = 1.0f; + } + + float PERCP = PERCF * FRACP; + float PERCS = PERCF - PERCP; + // PERCP and PERCS are the amount of excess percolation + // going to primary and supplemental storages, respectively + + cNode->LZFSC += PERCS; + if (cNode->LZFSC > cNode->params[PARAM_SAC_LZFSM]) { + PERCS = PERCS - cNode->LZFSC + cNode->params[PARAM_SAC_LZFSM]; + cNode->LZFSC = cNode->params[PARAM_SAC_LZFSM]; + } + + cNode->LZFPC = cNode->LZFPC + PERCF - PERCS; + if (cNode->LZFPC > cNode->params[PARAM_SAC_LZFPM]) { + float EXCESS = cNode->LZFPC - cNode->params[PARAM_SAC_LZFPM]; + cNode->LZTWC += EXCESS; + cNode->LZFPC = cNode->params[PARAM_SAC_LZFPM]; + } + } + + // Distribute PINC between UZFWC & surface runoff + if (PINC != 0.0f) { + if ((PINC + cNode->UZFWC) <= cNode->params[PARAM_SAC_UZFWM]) { + // No surface runoff + cNode->UZFWC += PINC; + } else { + float SUR = PINC + cNode->UZFWC - cNode->params[PARAM_SAC_UZFWM]; + SSUR = SSUR + SUR * PAREA; + + ADSUR = SUR * (1.0f - ADDRO / PINC); + // ADSUR is the amount of surface runoff which comes from + // that portion of ADIMP which is not + // currently generating direct runoff. ADDRO/PINC is the fraction + // of ADIMP currently generating direct runoff. + + SSUR = SSUR + ADSUR * cNode->params[PARAM_SAC_ADIMP]; + } + } + + // ADIMP area water balance -- SDRO is the IDT sum of the direct runoff + cNode->ADIMC = cNode->ADIMC + PINC - ADDRO - ADSUR; + if (cNode->ADIMC > (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM])) { + ADDRO = ADDRO + cNode->ADIMC - (cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM]); + cNode->ADIMC = cNode->params[PARAM_SAC_UZTWM] + cNode->params[PARAM_SAC_LZTWM]; + } + + SDRO = SDRO + ADDRO * cNode->params[PARAM_SAC_ADIMP]; + if (cNode->ADIMC < 0.00001f) { + cNode->ADIMC = 0.0f; + } + } + + /****************************************/ + /* End of incremental Loop */ + /****************************************/ + + // Compute sums and adjust runoff amounts by the area over which they are generated + + float EUSED = E1 + E2 + E3; // ET from PAREA which is 1.0 - ADIMP - PCTIM + + SIF *= PAREA; + + // Separate channel component of baseflow from the non-channel component + float TBF = SBF * PAREA; // Total baseflow + float BFCC = TBF * (1.0f / (1.0f + cNode->params[PARAM_SAC_SIDE])); // Baseflow, channel component + + float BFP = SPBF * PAREA / (1.0f + cNode->params[PARAM_SAC_SIDE]); + float BFS = BFCC - BFP; + if (BFS < 0.0f) { + BFS = 0.0f; + } + //float BFNCC = TBF - BFCC; // Baseflow, non-channel component + + float TCI = ROIMP + SDRO + SSUR + SIF + BFCC; // Total channel inflow for the time interval + float GRND = SIF + BFCC; // interflow part of ground flow + float SURF = TCI - GRND; // interflow part of surface flow + + float E4 = (pet - EUSED) * cNode->params[PARAM_SAC_RIVA]; // / stepHours; // ET from Riparian vegetation + + static int II = 0; + //printf(" **** %i ****\n",II); + II++; + //printf(" %f %f %f %f %f %f %f\n", TCI, ROIMP, SDRO, SSUR, SIF, BFCC, NINC); + + TCI -= E4; + if (TCI < 0.0f) { + E4 += TCI; + TCI = 0.0f; + } + + GRND -= E4; + if (GRND < 0.0f) { + SURF += GRND; + GRND = 0.0f; + if (SURF < 0.0f) { + SURF = 0.0f; + } + } + + EUSED *= PAREA; + //float TET = EUSED + E5 + E4; // total evaportranspiration + if (cNode->ADIMC < cNode->UZTWC) { + cNode->ADIMC = cNode->UZTWC; + } + + cNode->dischargeF = SURF; + cNode->dischargeS = GRND; + + //printf(" %f %f %f %f %f\n", EUSED, E5, E4, pet, cNode->params[PARAM_SAC_RIVA]); + //printf(" %f %f %f\n", SURF, GRND, TET); + //printf("1: %f %f %f %f %f %f", cNode->UZTWC, cNode->UZFWC, cNode->LZTWC, cNode->LZFSC, cNode->LZFPC, cNode->ADIMC); + +} + +void SAC::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + for (std::vector<GridNode>::iterator itr = nodes->begin(); itr != nodes->end(); itr++) { + GridNode *node = &(*itr); + SACGridNode *cNode = (SACGridNode*)node->modelNode; + if (!node->gauge) { + continue; + } + + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_SAC_QTY); + + // Initialize states + cNode->UZTWC = cNode->params[PARAM_SAC_UZTWC] * cNode->params[PARAM_SAC_UZTWM]; //0.0f; + cNode->UZFWC = cNode->params[PARAM_SAC_UZFWC] * cNode->params[PARAM_SAC_UZFWM]; //0.0f; //2.773; + cNode->LZTWC = cNode->params[PARAM_SAC_LZTWC] * cNode->params[PARAM_SAC_LZTWM]; //0.0f; //286.7; + cNode->LZFSC = cNode->params[PARAM_SAC_LZFSC] * cNode->params[PARAM_SAC_LZFSM]; //0.0f; + cNode->LZFPC = cNode->params[PARAM_SAC_LZFPC] * cNode->params[PARAM_SAC_LZFPM]; //0.0f; //154.2; + cNode->ADIMC = cNode->params[PARAM_SAC_ADIMC]; //:x0.0f; + + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_CREST_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] != grid->noData) { + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + } + } +} diff --git a/src/SAC.h b/src/SAC.h new file mode 100755 index 0000000..5d42817 --- /dev/null +++ b/src/SAC.h @@ -0,0 +1,36 @@ +#ifndef SAC_H +#define SAC_H + +#include "ModelBase.h" + +struct SACGridNode : BasicGridNode { + + float params[PARAM_SAC_QTY]; + + float UZTWC, UZFWC, LZTWC, LZFSC, LZFPC, ADIMC; + float dischargeF, dischargeS; +}; + +class SAC : public WaterBalanceModel { + + public: + SAC(); + ~SAC(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeStates(TimeVar *beginTime, char *statePath); + void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter); + bool WaterBalance(float stepHours, std::vector<float> *precip, std::vector<float> *pet, std::vector<float> *fastFlow, std::vector<float> *slowFlow, std::vector<float> *soilMoisture); + bool IsLumped() { return false; } + const char *GetName() { return "sac"; } + + private: + void WaterBalanceInt(GridNode *node, SACGridNode *cNode, float stepHours, float precipIn, float petIn); + //void LocalRouteQF(GridNode *node, HyMODGridNode *cNode); + //void LocalRouteSF(GridNode *node, HyMODGridNode *cNode); + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + + std::vector<GridNode> *nodes; + std::vector<SACGridNode> sacNodes; +}; + +#endif diff --git a/src/SimpleInundation.cpp b/src/SimpleInundation.cpp new file mode 100755 index 0000000..e9adb0b --- /dev/null +++ b/src/SimpleInundation.cpp @@ -0,0 +1,117 @@ +#include <cstdio> +#include <cstring> +#include <cmath> +#include "DatedName.h" +#include "SimpleInundation.h" + +SimpleInundation::SimpleInundation() { + +} + +SimpleInundation::~SimpleInundation() { + +} + +bool SimpleInundation::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (iNodes.size() != nodes->size()) { + iNodes.resize(nodes->size()); + } + + InitializeParameters(paramSettings, paramGrids); + + // Fill in modelIndex in the gridNodes + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + node->modelIndex = i; + } + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + GridNode *channelNode = node; + node->modelIndex = i; + while (!channelNode->channelGridCell && channelNode->downStreamNode != INVALID_DOWNSTREAM_NODE) { + channelNode = &nodes->at(channelNode->downStreamNode); + } + iNodes[i].params[PARAM_SI_ALPHA] = iNodes[channelNode->index].params[PARAM_SI_ALPHA]; + iNodes[i].params[PARAM_SI_BETA] = iNodes[channelNode->index].params[PARAM_SI_BETA]; + iNodes[i].elevation = g_DEM->data[node->y][node->x]; + iNodes[i].elevationChannel = g_DEM->data[channelNode->y][channelNode->x]; + iNodes[i].elevDiff = iNodes[i].elevation - iNodes[i].elevationChannel; + iNodes[i].channelIndex = channelNode->index; + } + + + + return true; +} + +bool SimpleInundation::Inundation(std::vector<float> *discharge, std::vector<float> *depth) { + + size_t numNodes = nodes->size(); + + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + InundationGridNode *cNode = &(iNodes[i]); + //InundationGridNode *channelNode = &(iNodes[cNode->channelIndex]); + InundationInt(node, cNode, discharge->at(cNode->channelIndex), &(depth->at(i))); + } + + return true; +} + +void SimpleInundation::InundationInt(GridNode *node, InundationGridNode *cNode, float dischargeIn, float *depth) { + + //float area = powf(dischargeIn/cNode->params[PARAM_SI_ALPHA], 1.0/cNode->params[PARAM_SI_BETA]); + //float z1 = 3.0, z2 = 3.0, b = 100.0; + //float b= 50.0; + float height = cNode->params[PARAM_SI_ALPHA]*powf(dischargeIn, cNode->params[PARAM_SI_BETA]);//area/b; //(-b + sqrtf(powf(b, 2.0) - 4.0 * area * (z1+z2))) / (2.0 * (z1+z2)); + //if (node->channelGridCell && dischargeIn != 0.0) { + // printf("Have Q %f, area %f, height %f, elev %f\n", dischargeIn, area, height, cNode->elevDiff); + //} + float d = height - cNode->elevDiff; + if (d < 0.0) { + d = 0.0; + } + *depth = d; + + +} + +void SimpleInundation::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + size_t numNodes = nodes->size(); + size_t unused = 0; + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + InundationGridNode *cNode = &(iNodes[i]); + if (!node->gauge) { + unused++; + continue; + } + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_SI_QTY); + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_SI_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && g_DEM->IsSpatialMatch(grid)) { + if (grid->data[node->y][node->x] == 0) { + grid->data[node->y][node->x] = 0.01; + } + cNode->params[paramI] *= grid->data[node->y][node->x]; + } else if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] == 0) { + grid->data[pt.y][pt.x] = 0.01; + //printf("Using nodata value in param %s\n", modelParamStrings[MODEL_CREST][paramI]); + } + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + + } + +} diff --git a/src/SimpleInundation.h b/src/SimpleInundation.h new file mode 100755 index 0000000..d8705db --- /dev/null +++ b/src/SimpleInundation.h @@ -0,0 +1,34 @@ +#ifndef SI_MODEL_H +#define SI_MODEL_H + +#include "ModelBase.h" + +struct InundationGridNode : BasicGridNode { + float params[PARAM_SI_QTY]; + + float elevation; + float elevationChannel; + float elevDiff; + unsigned long channelIndex; + +}; + +class SimpleInundation : public InundationModel { + +public: + SimpleInundation(); + ~SimpleInundation(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + bool Inundation(std::vector<float> *discharge, std::vector<float> *depth); + const char *GetName() { return "simpleinundation"; } + +private: + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InundationInt(GridNode *node, InundationGridNode *cNode, float dischargeIn, float *depth); + + std::vector<GridNode> *nodes; + std::vector<InundationGridNode> iNodes; + +}; + +#endif diff --git a/src/Simulator.cpp b/src/Simulator.cpp new file mode 100755 index 0000000..5e0ef47 --- /dev/null +++ b/src/Simulator.cpp @@ -0,0 +1,2093 @@ +#include <cstdio> +#include <cstring> +#include <sys/stat.h> +#if _OPENMP +#include <omp.h> +#endif +#include <cmath> +#include <string.h> +#include <zlib.h> +#include "Messages.h" +#include "BasicGrids.h" +#include "CRESTModel.h" +#include "HyMOD.h" +#include "SAC.h" +#include "HPModel.h" +#include "LinearRoute.h" +#include "KinematicRoute.h" +#include "Snow17Model.h" +#include "SimpleInundation.h" +#include "VCInundation.h" +#include "PETConfigSection.h" +#include "PrecipConfigSection.h" +#include "TifGrid.h" +#include "GridWriterFull.h" +#include "GriddedOutput.h" +#include "Simulator.h" + +bool Simulator::Initialize(TaskConfigSection *taskN) { + + task = taskN; + + if (!InitializeBasic(task)) { + return false; + } + + if (task->GetRunStyle() == STYLE_SIMU || task->GetRunStyle() == STYLE_SIMU_RP || task->GetRunStyle() == STYLE_BASIN_AVG) { + // We are a simulation run + if (!InitializeSimu(task)) { + return false; + } + } else { + // Must be a calibration run + if (!InitializeCali(task)) { + return false; + } + } + + LoadDAFile(task); + + // Everything succeeded! + return true; +} + +bool Simulator::InitializeBasic(TaskConfigSection *task) { + // Initialize time step information + inLR = false; + timeStep = task->GetTimeStep(); + timeStepSR = task->GetTimeStep(); + timeStepLR = task->GetTimeStepLR(); + timeStepPrecip = task->GetPrecipSec()->GetFreq(); + if (task->GetQPFSec()) { + hasQPF = true; + timeStepQPF = task->GetQPFSec()->GetFreq(); + } else { + hasQPF = false; + } + timeStepPET = task->GetPETSec()->GetFreq(); + + if (task->GetSnow() != SNOW_QTY) { + timeStepTemp = task->GetTempSec()->GetFreq(); + if (task->GetTempFSec()) { + hasTempF = true; + timeStepTempF = task->GetTempFSec()->GetFreq(); + } else { + hasTempF = false; + } + } else { + timeStepTemp = NULL; + } + + // Initialize unit converters + precipConvert = (3600.0 / (float)task->GetPrecipSec()->GetUnitTime()->GetTimeInSec()); + if (hasQPF) { + qpfConvert = (3600.0 / (float)task->GetQPFSec()->GetUnitTime()->GetTimeInSec()); + } + if (!task->GetPETSec()->IsTemperature()) { + petConvert = (3600.0 / (float)task->GetPETSec()->GetUnitTime()->GetTimeInSec()); + } else { + petConvert = 1.0; + } + timeStepHours = timeStep->GetTimeInSec() / 3600.0; + + if (timeStepLR) { + timeStepHoursLR = timeStepLR->GetTimeInSec() / 3600.0; + beginLRTime = *(task->GetTimeBeginLR()); + } + + // Initialize time information + currentTime = *(task->GetTimeBegin()); + currentTimePrecip = *(task->GetTimeBegin()); + currentTimeQPF = *(task->GetTimeBegin()); + currentTimePET = *(task->GetTimeBegin()); + currentTimeTemp = *(task->GetTimeBegin()); + currentTimeTempF = *(task->GetTimeBegin()); + beginTime = *(task->GetTimeBegin()); + endTime = *(task->GetTimeEnd()); + warmEndTime = *(task->GetTimeWarmEnd()); + + // Initialize file name information + precipFile = task->GetPrecipSec()->GetFileName(); + if (hasQPF) { + qpfFile = task->GetQPFSec()->GetFileName(); + } + petFile = task->GetPETSec()->GetFileName(); + if (task->GetSnow() != SNOW_QTY) { + tempFile = task->GetTempSec()->GetFileName(); + if (hasTempF) { + tempFFile = task->GetTempFSec()->GetFileName(); + } + } + currentTimeText.SetNameStr("YYYY-MM-DD HH:UU"); + currentTimeText.ProcessNameLoose(NULL); + currentTimeTextOutput.SetNameStr("YYYYMMDD_HHUU"); + currentTimeTextOutput.ProcessNameLoose(NULL); + + // Set forcing info + precipSec = task->GetPrecipSec(); + petSec = task->GetPETSec(); + qpfSec = task->GetQPFSec(); + tempSec = task->GetTempSec(); + tempFSec = task->GetTempFSec(); + + // Initialize our gauges + gauges = task->GetBasinSec()->GetGauges(); + + // Initialize parameter settings + paramSettings = task->GetParamsSec()->GetParamSettings(); + if (task->GetRouting() != ROUTE_QTY) { + paramSettingsRoute = task->GetRoutingParamsSec()->GetParamSettings(); + } else { + paramSettingsRoute = NULL; + } + if (task->GetSnow() != SNOW_QTY) { + paramSettingsSnow = task->GetSnowParamsSec()->GetParamSettings(); + } else { + paramSettingsSnow = NULL; + } + + if (task->GetInundation() != INUNDATION_QTY) { + paramSettingsInundation = task->GetInundationParamsSec()->GetParamSettings(); + } else { + paramSettingsInundation = NULL; + } + + // Initialize gridded parameter settings + if (!InitializeGridParams(task)) { + return false; + } + + float *defaultParams = NULL, *defaultParamsRoute = NULL, *defaultParamsSnow = NULL, *defaultParamsInundation = NULL; + GaugeConfigSection *gs = task->GetDefaultGauge(); + std::map<GaugeConfigSection *, float *>::iterator pitr = paramSettings->find(gs); + if (pitr != paramSettings->end()) { + defaultParams = pitr->second; + } + + // Repeat for routing params + if (task->GetRouting() != ROUTE_QTY) { + pitr = paramSettingsRoute->find(gs); + if (pitr != paramSettingsRoute->end()) { + defaultParamsRoute = pitr->second; + } + } + + // Repeat for snow params + if (task->GetSnow() != SNOW_QTY) { + pitr = paramSettingsSnow->find(gs); + if (pitr != paramSettingsSnow->end()) { + defaultParamsSnow = pitr->second; + } + } + + // Repeat for inundation params + if (task->GetInundation() != INUNDATION_QTY) { + pitr = paramSettingsInundation->find(gs); + if (pitr != paramSettingsInundation->end()) { + defaultParamsInundation = pitr->second; + } + } + + // Carve the basin to find which nodes we're modeling on + CarveBasin(task->GetBasinSec(), &nodes, paramSettings, &fullParamSettings, &gaugeMap, defaultParams, paramSettingsRoute, &fullParamSettingsRoute, defaultParamsRoute, paramSettingsSnow, &fullParamSettingsSnow, defaultParamsSnow, paramSettingsInundation, &fullParamSettingsInundation, defaultParamsInundation); + + // Ensure we actually have at least one node to work with! + if (nodes.size() == 0) { + ERROR_LOG("The number of grid cells in which we are modeling is 0! (Invalid gauge location?)"); + return false; + } + + // Create the appropriate model + switch (task->GetModel()) { + case MODEL_CREST: + wbModel = new CRESTModel(); + break; + case MODEL_HYMOD: + wbModel = new HyMOD(); + break; + case MODEL_SAC: + wbModel = new SAC(); + break; + case MODEL_HP: + wbModel = new HPModel(); + break; + default: + ERROR_LOG("Unsupported Water Balance Model!!"); + return false; + } + + if (wbModel->IsLumped()) { + // We need to provided updated areas + std::vector<float> gaugeAreas; + gaugeAreas.resize(gauges->size()); + gaugeMap.GetGaugeArea(&nodes, &gaugeAreas); + + lumpedNodes.resize(gauges->size()); + for (size_t i = 0; i < gauges->size(); i++) { + GaugeConfigSection *gauge = gauges->at(i); + memcpy(&(lumpedNodes[i]), &(nodes[gauge->GetGridNodeIndex()]), sizeof(GridNode)); + lumpedNodes[i].area = gaugeAreas[i]; + } + rModel = NULL; + } else { + // Create the appropriate routing + switch (task->GetRouting()) { + case ROUTE_LINEAR: + rModel = new LRRoute(); + break; + case ROUTE_KINEMATIC: + rModel = new KWRoute(); + break; + case ROUTE_QTY: + rModel = NULL; + break; + default: + ERROR_LOG("Unsupported Routing Model!!"); + return false; + } + } + + // Create the appropriate snow model + switch (task->GetSnow()) { + case SNOW_SNOW17: + sModel = new Snow17Model(); + break; + case SNOW_QTY: + sModel = NULL; + break; + default: + ERROR_LOG("Unsupported Snow Model!!"); + return false; + } + + switch (task->GetInundation()) { + case INUNDATION_SI: + iModel = new SimpleInundation(); + break; + case INUNDATION_VCI: + iModel = new VCInundation(); + break; + case INUNDATION_QTY: + iModel = NULL; + break; + default: + ERROR_LOG("Unsupported inundation model!!"); + return false; + } + + gaugesUsed.resize(gauges->size()); + for (size_t i = 0; i < gauges->size(); i++) { + gaugesUsed[i] = false; + } + + return true; +} + +bool Simulator::InitializeSimu(TaskConfigSection *task) { + + char buffer[CONFIG_MAX_LEN*2]; + + griddedOutputs = task->GetGriddedOutputs(); + useStates = task->UseStates(); + saveStates = task->SaveStates(); + + // Initialize the storage of contributing precip & PET + avgPrecip.resize(gauges->size()); + avgPET.resize(gauges->size()); + avgSWE.resize(gauges->size()); + avgT.resize(gauges->size()); + avgSM.resize(gauges->size()); + avgFF.resize(gauges->size()); + avgSF.resize(gauges->size()); + + // Initialize forcing vectors & discharge storage vector + currentPrecipSimu.resize(nodes.size()); + currentPETSimu.resize(nodes.size()); + currentTempSimu.resize(nodes.size()); + if (!wbModel->IsLumped()) { + if (task->GetStdGrid()[0] && task->GetAvgGrid()[0] && task->GetScGrid()[0]) { + std::vector<float> avgVals, stdVals, scVals; + avgVals.resize(nodes.size()); + stdVals.resize(nodes.size()); + scVals.resize(nodes.size()); + if (ReadLP3File(task->GetStdGrid(), &nodes, &stdVals) && ReadLP3File(task->GetAvgGrid(), &nodes, &avgVals) && ReadLP3File(task->GetScGrid(), &nodes, &scVals)) { + outputRP = true; + rpData.resize(nodes.size()); + CalcLP3Vals(&stdVals, &avgVals, &scVals, &rpData, &nodes); + } else { + ERROR_LOGF("%s", "Failed to load LP3 grids!"); + outputRP = false; + } + } else { + outputRP = false; + } + currentFF.resize(nodes.size()); + currentSF.resize(nodes.size()); + currentQ.resize(nodes.size()); + currentSWE.resize(nodes.size()); + currentDepth.resize(nodes.size()); + } else { + outputRP = false; + currentFF.resize(lumpedNodes.size()); + currentSF.resize(lumpedNodes.size()); + currentQ.resize(lumpedNodes.size()); + currentSWE.resize(lumpedNodes.size()); + } + + // Initialize file handles for all of the gauges we are using! Also load the time series information if appropriate. + gaugeOutputs.resize(gauges->size()); + for (size_t i = 0; i < gauges->size(); i++) { + gaugeOutputs[i] = NULL; + if (gauges->at(i)->OutputTS()) { + sprintf(buffer, "%s/ts.%s.%s.csv", task->GetOutput(), gauges->at(i)->GetName(), wbModel->GetName()); + gaugeOutputs[i] = fopen(buffer, "w"); + if (gaugeOutputs[i]) { + //setvbuf(gaugeOutputs[i], NULL, _IONBF, 0); + fprintf(gaugeOutputs[i], "%s", "Time,Discharge(m^3 s^-1),Observed(m^3 s^-1),Precip(mm h^-1),PET(mm h^-1),SM(%),Fast Flow(mm*1000),Slow Flow(mm*1000)"); + if (sModel) { + fprintf(gaugeOutputs[i], "%s", ",Temperature (C),SWE(mm)"); + } + if (outputRP) { + fprintf(gaugeOutputs[i], "%s", ",Return Period(y)"); + } + fprintf(gaugeOutputs[i], "%s", "\n"); + + } else { + WARNING_LOGF("Failed to open gauge output file \"%s\"", buffer); + } + } + + // Tell this gauge to load the observed data file + gauges->at(i)->LoadTS(); + // NORMAL_LOGF("%s\n", "Got here!1"); + } + + outputPath = task->GetOutput(); + if (useStates) { + statePath = task->GetState(); + stateTime = *(task->GetTimeState()); + } + + if ((task->GetPreloadForcings())[0]) { + totalTimeSteps = 0; + for (currentTime.Increment(timeStep); currentTime <= endTime; currentTime.Increment(timeStep)) { + if (timeStepLR && !inLR && beginLRTime <= currentTime) { + inLR = true; + timeStep = timeStepLR; + } + totalTimeSteps++; + } + inLR = false; + timeStep = timeStepSR; + currentPrecipCali.resize(totalTimeSteps); + currentPETCali.resize(totalTimeSteps); + currentTempCali.resize(totalTimeSteps); + sprintf(buffer, "%s/%s", task->GetOutput(), task->GetPreloadForcings()); + INFO_LOGF("Preloading forcing from file %s", buffer); + PreloadForcings(buffer, false); + currentTime = beginTime; + preloadedForcings = true; + } else { + preloadedForcings = false; + } + + return true; +} + +bool Simulator::InitializeCali(TaskConfigSection *task) { + + // Set calibration param info + caliParamSec = task->GetCaliParamSec(); + routingCaliParamSec = task->GetRoutingCaliParamSec(); + snowCaliParamSec = task->GetSnowCaliParamSec(); + objectiveFunc = caliParamSec->GetObjFunc(); + caliGauge = caliParamSec->GetGauge(); + numWBParams = numModelParams[task->GetModel()]; + if (task->GetRouting() != ROUTE_QTY) { + numRParams = numRouteParams[task->GetRouting()]; + } else { + numRParams = 0; + } + if (task->GetSnow() != SNOW_QTY) { + numSParams = numSnowParams[task->GetSnow()]; + } else { + numSParams = 0; + } + + if (timeStepLR) { + ERROR_LOGF("%s", "Long range time steps do not work in calibration mode!"); + return false; + } + + INFO_LOGF("Calibrating on gauge %s", caliGauge->GetName()); + + // See if we have the approriate parameters set to do this + if (paramSettings->find(caliGauge) == paramSettings->end()) { + ERROR_LOGF("In order to calibrate on gauge \"%s\" it must be given parameter settings. They can not be inferred from a downstream gauge!", caliGauge->GetName()); + return false; + } + caliWBParams = fullParamSettings[caliGauge]; + + if (task->GetRouting() != ROUTE_QTY) { + // See if we have the approriate routing parameters set to do this + if (paramSettingsRoute->find(caliGauge) == paramSettingsRoute->end()) { + ERROR_LOGF("In order to calibrate on gauge \"%s\" it must be given routing parameter settings. They can not be inferred from a downstream gauge!", caliGauge->GetName()); + return false; + } + caliRParams = fullParamSettingsRoute[caliGauge]; + } + + if (task->GetSnow() != SNOW_QTY) { + // See if we have the approriate routing parameters set to do this + if (paramSettingsSnow->find(caliGauge) == paramSettingsSnow->end()) { + ERROR_LOGF("In order to calibrate on gauge \"%s\" it must be given snow parameter settings. They can not be inferred from a downstream gauge!", caliGauge->GetName()); + return false; + } + caliSParams = fullParamSettingsSnow[caliGauge]; + } + + caliGauge->LoadTS(); + + // Figure out how many time steps there are going to be + totalTimeSteps = 0; totalTimeStepsOutsideWarm = 0; + for (currentTime.Increment(timeStep); currentTime <= endTime; currentTime.Increment(timeStep)) { + totalTimeSteps++; + if (warmEndTime <= currentTime) { + totalTimeStepsOutsideWarm++; + } + } + + // Initialize storage for forcing vectors + currentPrecipCali.resize(totalTimeSteps); + currentPETCali.resize(totalTimeSteps); + if (task->GetSnow() != SNOW_QTY) { + currentTempCali.resize(totalTimeSteps); + } + if (!wbModel->IsLumped()) { + currentFF.resize(nodes.size()); + currentSF.resize(nodes.size()); + currentQ.resize(nodes.size()); + currentSWE.resize(nodes.size()); + } else { + currentFF.resize(lumpedNodes.size()); + currentSF.resize(lumpedNodes.size()); + currentQ.resize(lumpedNodes.size()); + currentSWE.resize(lumpedNodes.size()); + } + + // Initialize storage for discharge vectors + obsQ.resize(totalTimeStepsOutsideWarm); + simQ.resize(totalTimeStepsOutsideWarm); + + // Get caliGaugeIndex + for (size_t i = 0; i < gauges->size(); i++) { + if (caliGauge == gauges->at(i)) { + caliGaugeIndex = i; + break; + } + } + + // Initialize our parallel model sets if using OpenMP +#if _OPENMP + int maxThreads = omp_get_max_threads(); + caliWBModels.resize(maxThreads); + caliRModels.resize(maxThreads); + caliSModels.resize(maxThreads); + caliWBFullParamSettings.resize(maxThreads); + caliWBCurrentParams.resize(maxThreads); + caliRFullParamSettings.resize(maxThreads); + caliRCurrentParams.resize(maxThreads); + caliSFullParamSettings.resize(maxThreads); + caliSCurrentParams.resize(maxThreads); + for (int i = 0; i < maxThreads; i++) { + switch (task->GetModel()) { + case MODEL_CREST: + caliWBModels[i] = new CRESTModel(); + break; + case MODEL_HYMOD: + caliWBModels[i] = new HyMOD(); + break; + case MODEL_SAC: + caliWBModels[i] = new SAC(); + break; + case MODEL_HP: + caliWBModels[i] = new HPModel(); + break; + default: + ERROR_LOG("Unsupported Model!!"); + return false; + } + + // Create the appropriate routing + switch (task->GetRouting()) { + case ROUTE_LINEAR: + caliRModels[i] = new LRRoute(); + break; + case ROUTE_KINEMATIC: + caliRModels[i] = new KWRoute(); + break; + case ROUTE_QTY: + caliRModels[i] = NULL; + break; + default: + ERROR_LOG("Unsupported Routing Model!!"); + return false; + } + + // Create the appropriate snow model + switch (task->GetSnow()) { + case SNOW_SNOW17: + caliSModels[i] = new Snow17Model(); + break; + case SNOW_QTY: + caliSModels[i] = NULL; + break; + default: + ERROR_LOG("Unsupported Snow Model!!"); + return false; + } + + + caliWBCurrentParams[i] = new float[numWBParams]; + + for (std::map<GaugeConfigSection *, float *>::iterator itr = fullParamSettings.begin(); itr != fullParamSettings.end(); itr++) { + if (itr->second == caliWBParams) { + (caliWBFullParamSettings[i])[itr->first] = caliWBCurrentParams[i]; + } else { + (caliWBFullParamSettings[i])[itr->first] = itr->second; + } + } + + if (task->GetRouting() != ROUTE_QTY) { + caliRCurrentParams[i] = new float[numRParams]; + for (std::map<GaugeConfigSection *, float *>::iterator itr = fullParamSettingsRoute.begin(); itr != fullParamSettingsRoute.end(); itr++) { + if (itr->second == caliRParams) { + (caliRFullParamSettings[i])[itr->first] = caliRCurrentParams[i]; + } else { + (caliRFullParamSettings[i])[itr->first] = itr->second; + } + } + } + + if (task->GetSnow() != SNOW_QTY) { + caliSCurrentParams[i] = new float[numSParams]; + + for (std::map<GaugeConfigSection *, float *>::iterator itr = fullParamSettingsSnow.begin(); itr != fullParamSettingsSnow.end(); itr++) { + if (itr->second == caliSParams) { + (caliSFullParamSettings[i])[itr->first] = caliSCurrentParams[i]; + } else { + (caliSFullParamSettings[i])[itr->first] = itr->second; + } + } + } + } +#endif + + return true; +} + +void Simulator::CleanUp() { + // Close output gauge files + for (size_t i = 0; i < gaugeOutputs.size(); i++) { + if (gaugeOutputs[i]) { + fclose(gaugeOutputs[i]); + } + } +} + +void Simulator::BasinAvg() { + PrecipReader precipReader; + char buffer[CONFIG_MAX_LEN*2]; +#if _OPENMP + double timeTotal = 0.0, timeCount = 0.0; +#endif + + std::vector<float> avgVals; + long numNodes = nodes.size(); + avgVals.resize(numNodes); + + gridWriter.Initialize(); + + // This is the temporal loop for each time step + // Here we load the input forcings & actually run the model + for (currentTime.Increment(timeStep); currentTime <= endTime; currentTime.Increment(timeStep)) { +#if _OPENMP +#ifndef _WIN32 + double beginTime = omp_get_wtime(); +#endif +#endif + currentTimeText.UpdateName(currentTime.GetTM()); +#ifndef _WIN32 + NORMAL_LOGF("%s", currentTimeText.GetName()); +#else + setTimestep(currentTimeText.GetName()); +#endif + + currentTimeTextOutput.UpdateName(currentTime.GetTM()); + + LoadForcings(&precipReader, NULL, NULL); + + for (long i = numNodes - 1; i >= 0; i--) { + GridNode *node = &(nodes[i]); + float addVal = avgVals[i] + currentPrecipSimu[i]; + avgVals[i] = addVal / nodes[i].contribArea; + if (node->downStreamNode != INVALID_DOWNSTREAM_NODE) { + avgVals[node->downStreamNode] += addVal; + } + } + + sprintf(buffer, "%s/precip.%s.avg.tif", outputPath, currentTimeTextOutput.GetName()); + gridWriter.WriteGrid(&nodes, &avgVals, buffer, false); + + for (long i = numNodes - 1; i >= 0; i--) { + avgVals[i] = 0.0; + } + +#if _OPENMP +#ifndef _WIN32 + double endTime = omp_get_wtime(); + double timeDiff = endTime - beginTime; + NORMAL_LOGF(" %f sec", endTime - beginTime); + timeTotal += timeDiff; + timeCount++; + if (timeCount == 250) { + NORMAL_LOGF(" (%f sec avg)", timeTotal / timeCount); + timeCount = 0.0; + timeTotal = 0.0; + } +#endif +#endif + + // All of our status messages are done for this timestep! +#ifndef _WIN32 + NORMAL_LOGF("%s", "\n"); +#endif + + } + + for (long i = numNodes - 1; i >= 0; i--) { + float areaUsed = (nodes[i].contribArea > 100000.0) ? 100000.0 : nodes[i].contribArea; + areaUsed = (areaUsed < 3.0) ? 3.0 : areaUsed; + avgVals[i] = 0.000503442*powf(areaUsed, -0.47)*powf(currentPrecipSimu[i],1.25)*nodes[i].contribArea; + avgVals[i] = 0.3012*powf(avgVals[i],1.1894); + //avgVals[i] = 8.24*powf(areaUsed, -0.57)*nodes[i].contribArea; + } + sprintf(buffer, "%s/actionFloodThresPrecip.tif", outputPath); + gridWriter.WriteGrid(&nodes, &avgVals, buffer, false); + + for (long i = numNodes - 1; i >= 0; i--) { + float areaUsed = (nodes[i].contribArea > 100000.0) ? 100000.0 : nodes[i].contribArea; + areaUsed = (areaUsed < 3.0) ? 3.0 : areaUsed; + avgVals[i] = 0.00078398*powf(areaUsed, -0.47)*powf(currentPrecipSimu[i],1.25)*nodes[i].contribArea; + avgVals[i] = 0.3012*powf(avgVals[i],1.1894); + //avgVals[i] = 8.24*powf(areaUsed, -0.57)*nodes[i].contribArea; + } + sprintf(buffer, "%s/minorFloodThresPrecip.tif", outputPath); + gridWriter.WriteGrid(&nodes, &avgVals, buffer, false); + + for (long i = numNodes - 1; i >= 0; i--) { + float areaUsed = (nodes[i].contribArea > 100000.0) ? 100000.0 : nodes[i].contribArea; + areaUsed = (areaUsed < 3.0) ? 3.0 : areaUsed; + avgVals[i] = 0.001308855*powf(areaUsed, -0.47)*powf(currentPrecipSimu[i],1.25)*nodes[i].contribArea; + avgVals[i] = 0.3012*powf(avgVals[i],1.1894); + //avgVals[i] = 8.24*powf(areaUsed, -0.57)*nodes[i].contribArea; + } + sprintf(buffer, "%s/moderateFloodThresPrecip.tif", outputPath); + gridWriter.WriteGrid(&nodes, &avgVals, buffer, false); + + for (long i = numNodes - 1; i >= 0; i--) { + float areaUsed = (nodes[i].contribArea > 100000.0) ? 100000.0 : nodes[i].contribArea; + areaUsed = (areaUsed < 3.0) ? 3.0 : areaUsed; + avgVals[i] = 0.001995269*powf(areaUsed, -0.47)*powf(currentPrecipSimu[i],1.25)*nodes[i].contribArea; + avgVals[i] = 0.3012*powf(avgVals[i],1.1894); + //avgVals[i] = 8.24*powf(areaUsed, -0.57)*nodes[i].contribArea; + } + sprintf(buffer, "%s/majorFloodThresPrecip.tif", outputPath); + gridWriter.WriteGrid(&nodes, &avgVals, buffer, false); + + for (long i = numNodes - 1; i >= 0; i--) { + float areaUsed = (nodes[i].contribArea > 100000.0) ? 100000.0 : nodes[i].contribArea; + areaUsed = (areaUsed < 3.0) ? 3.0 : areaUsed; + avgVals[i] = 8.502339237*powf(areaUsed, -0.57)*nodes[i].contribArea; + } + sprintf(buffer, "%s/minorFloodThres.tif", outputPath); + gridWriter.WriteGrid(&nodes, &avgVals, buffer, false); + + /*std::vector<float> rpavgVals, stdVals, scVals; + rpavgVals.resize(nodes.size()); + stdVals.resize(nodes.size()); + scVals.resize(nodes.size()); + if (ReadLP3File(task->GetStdGrid(), &nodes, &stdVals) && ReadLP3File(task->GetAvgGrid(), &nodes, &rpavgVals) && ReadLP3File(task->GetScGrid(), &nodes, &scVals)) { + rpData.resize(nodes.size()); + CalcLP3Vals(&stdVals, &rpavgVals, &scVals, &rpData, &nodes); + for (long i = numNodes - 1; i >= 0; i--) { + avgVals[i] = rpData[i].q5; + } + sprintf(buffer, "%s/q_5.tif", outputPath); + gridWriter.WriteGrid(&nodes, &avgVals, buffer, false); + }*/ + +} + +void Simulator::Simulate(bool trackPeaks) { + + if (!wbModel->IsLumped()) { + SimulateDistributed(trackPeaks); + } else { + SimulateLumped(); + } + +} + +float Simulator::GetNumSimulatedYears() { + int currentYear = -1; + float numYears = 0; + TimeVar tempTime = warmEndTime; + for (tempTime.Increment(timeStep); tempTime <= endTime; tempTime.Increment(timeStep)) { + if (tempTime.GetTM()->tm_year != currentYear) { + numYears++; + currentYear = tempTime.GetTM()->tm_year; + } + } + return numYears; +} + +int Simulator::LoadForcings(PrecipReader *precipReader, PETReader *petReader, TempReader *tempReader) { + char buffer[CONFIG_MAX_LEN*2], qpfBuffer[CONFIG_MAX_LEN*2]; + int retVal = 0; +#ifdef _WIN32 + bool outputError = false; +#endif + if (currentTimePrecip < currentTime) { + currentTimePrecip.Increment(timeStepPrecip); + precipFile->UpdateName(currentTimePrecip.GetTM()); + } + + if (hasQPF && currentTimeQPF < currentTime) { + currentTimeQPF.Increment(timeStepQPF); + qpfFile->UpdateName(currentTimeQPF.GetTM()); + } + + if (currentTimePET < currentTime) { + currentTimePET.Increment(timeStepPET); + petFile->UpdateName(currentTimePET.GetTM()); + } + + if (sModel && tempReader) { + if (currentTimeTemp < currentTime) { + currentTimeTemp.Increment(timeStepTemp); + tempFile->UpdateName(currentTimeTemp.GetTM()); + } + + if (hasTempF && currentTimeTempF < currentTime) { + currentTimeTempF.Increment(timeStepTempF); + tempFFile->UpdateName(currentTimeTempF.GetTM()); + } + + sprintf(buffer, "%s/%s", tempSec->GetLoc(), tempFile->GetName()); + if (!tempReader->Read(buffer, tempSec->GetType(), &nodes, ¤tTempSimu, NULL, hasTempF)) { + if (hasTempF) { + sprintf(qpfBuffer, "%s/%s", tempFSec->GetLoc(), tempFFile->GetName()); + } + if (!hasTempF || !tempReader->Read(qpfBuffer, tempSec->GetType(), &nodes, ¤tTempSimu, NULL, false)) { +#ifdef _WIN32 + outputError = true; +#endif + NORMAL_LOGF(" Missing Temp file(%s%s%s)... Assuming zeros.", buffer, (!hasTempF)?"":"; ", (!hasTempF)?"":qpfBuffer); + } + } + } + + if (precipReader) { + sprintf(buffer, "%s/%s", precipSec->GetLoc(), precipFile->GetName()); + if (!precipReader->Read(buffer, precipSec->GetType(), &nodes, ¤tPrecipSimu, precipConvert, NULL, hasQPF)) { + if (hasQPF) { + sprintf(qpfBuffer, "%s/%s", qpfSec->GetLoc(), qpfFile->GetName()); + } + if (!hasQPF || !precipReader->Read(qpfBuffer, qpfSec->GetType(), &nodes, ¤tPrecipSimu, qpfConvert, NULL, false)) { +#ifdef _WIN32 + outputError = true; +#endif + NORMAL_LOGF(" Missing precip file(%s%s%s)... Assuming zeros.", buffer, (!hasQPF)?"":"; ", (!hasQPF)?"":qpfBuffer); + } else if (hasQPF) { + retVal = 1; + } + } + } + + if (petReader) { + sprintf(buffer, "%s/%s", petSec->GetLoc(), petFile->GetName()); + if (!petReader->Read(buffer, petSec->GetType(), &nodes, ¤tPETSimu, petConvert, petSec->IsTemperature(), (float)currentTime.GetTM()->tm_yday)) { +#ifdef _WIN32 + outputError = true; +#endif + NORMAL_LOGF(" Missing PET file(%s)... Assuming zeros.", buffer); + } +#ifdef _WIN32 + if (outputError) { + NORMAL_LOGF("%s", "\n"); + } +#endif + } + + return retVal; +} + +void Simulator::SaveLP3Params() { + char buffer[CONFIG_MAX_LEN*2]; + std::vector<float> avgGrid, stdGrid, csGrid; + avgGrid.resize(currentFF.size()); + stdGrid.resize(currentFF.size()); + csGrid.resize(currentFF.size()); + // Convert to log + for (size_t i = 0; i < currentFF.size(); i++) { + for (int j = 0; j < numYears; j++) { + if (peakVals[j][i] == 0.0) { + peakVals[j][i] = 0.0000001; + } + peakVals[j][i] = log10(peakVals[j][i]); + } + } + + // Calculate average + for (size_t i = 0; i < currentFF.size(); i++) { + for (int j = 0; j < numYears; j++) { + avgGrid[i] += peakVals[j][i]; + } + avgGrid[i] /= numYears; + } + + // Calculate standard deviation + for (size_t i = 0; i < currentFF.size(); i++) { + for (int j = 0; j < numYears; j++) { + stdGrid[i] += powf(peakVals[j][i] - avgGrid[i], 2.0); + } + stdGrid[i] /= (numYears - 1.0); + stdGrid[i] = sqrt(stdGrid[i]); + } + + // Calculate the skewness coefficient + for (size_t i = 0; i < currentFF.size(); i++) { + float total = 0.0; + for (int j = 0; j < numYears; j++) { + total += powf(peakVals[j][i] - avgGrid[i], 3.0); + } + float csNum = numYears*total; + float csDom = (numYears - 1.0) * (numYears - 2.0) * powf(stdGrid[i], 3.0); + csGrid[i] = csNum / csDom; + } + + sprintf(buffer, "%s/avgq.%s.tif", outputPath, wbModel->GetName()); + gridWriter.WriteGrid(&nodes, &avgGrid, buffer, false); + + sprintf(buffer, "%s/stdq.%s.tif", outputPath, wbModel->GetName()); + gridWriter.WriteGrid(&nodes, &stdGrid, buffer, false); + + sprintf(buffer, "%s/sc.%s.tif", outputPath, wbModel->GetName()); + gridWriter.WriteGrid(&nodes, &csGrid, buffer, false); +} + +void Simulator::SaveTSOutput() { + for (size_t i = 0; i < gauges->size(); i++) { + GaugeConfigSection *gauge = gauges->at(i); + if (gaugeOutputs[i]) { + fprintf(gaugeOutputs[i], "%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.4f,%.4f", currentTimeText.GetName(), currentQ[gauge->GetGridNodeIndex()], gauge->GetObserved(¤tTime), avgPrecip[i], avgPET[i], avgSM[i], avgFF[i]*1000.0, avgSF[i]*1000.0); + if (sModel) { + fprintf(gaugeOutputs[i], ",%.2f,%.2f", avgT[i], avgSWE[i]); + } + if (outputRP) { + fprintf(gaugeOutputs[i], ",%.2f", GetReturnPeriod(currentQ[gauge->GetGridNodeIndex()], &(rpData[gauge->GetGridNodeIndex()]))); + } + fprintf(gaugeOutputs[i], "%s", "\n"); + } + } +} + +bool Simulator::IsOutputTS() { + bool wantoutput = false; + for (size_t i = 0; i < gauges->size(); i++) { + if (gaugeOutputs[i]) { + wantoutput = true; + break; + } + } + if (!wantoutput) { + INFO_LOGF("%s", "No time series are being output!"); + } + return wantoutput; +} + +void Simulator::LoadDAFile(TaskConfigSection *task) { + wantsDA = false; + if ((task->GetDAFile())[0]) { + + FILE *tsFile = fopen(task->GetDAFile(), "rb"); + if (tsFile == NULL) { + WARNING_LOGF("Failed to open data assimilation file %s", task->GetDAFile()); + return; + } + wantsDA = true; + //Get number of file lines + int fileLines = 0, temp; + while ( (temp = fgetc(tsFile)) != EOF) { + fileLines += (temp == 10); + } + fseek(tsFile, 0, SEEK_SET); + + for (int i = 0; i < fileLines; i++) { + char bufferGauge[CONFIG_MAX_LEN], bufferTime[CONFIG_MAX_LEN]; + float dataValue; + if (fscanf(tsFile, "%[^,],%[^,],%f%*c", &(bufferGauge[0]), &(bufferTime[0]), &dataValue) == 3) { + for (size_t i = 0; i < gauges->size(); i++) { + if (!strcasecmp(gauges->at(i)->GetName(), bufferGauge)) { + gauges->at(i)->SetObservedValue(bufferTime, dataValue); + break; + } + } + } else { + fgets(bufferGauge, CONFIG_MAX_LEN, tsFile); + } + } + + fclose(tsFile); + } +} + +void Simulator::AssimilateData() { + char buffer[254]; + sprintf(buffer, "%s/da_log.csv", task->GetOutput()); + FILE *fp = fopen(buffer, "a"); + for (size_t i = 0; i < gauges->size(); i++) { + GaugeConfigSection *gauge = gauges->at(i); + if (!gauge->WantDA()) { + continue; + } + float obs = gauge->GetObserved(¤tTime, 3600.0); + if (obs == obs && obs > 0.0) { + float oldValue = rModel->SetObsInflow(gauge->GetGridNodeIndex(), obs); + //if (!gaugesUsed[i]) { + fprintf(fp, "%s,%s,%f,%f\n", gauge->GetName(), currentTimeText.GetName(), oldValue, obs); + gaugesUsed[i] = true; + //} + } + } + fclose(fp); +} + +void Simulator::OutputCombinedOutput() { + if (!task->GetCOFile()[0]) { + return; + } + FILE *fp = fopen(task->GetCOFile(), "a"); + for (size_t i = 0; i < gauges->size(); i++) { + GaugeConfigSection *gauge = gauges->at(i); + if (!gauge->WantCO()) { + continue; + } + fprintf(fp, "%s,%s,%f\n", currentTimeText.GetName(), gauge->GetName(), currentQ[gauge->GetGridNodeIndex()]); + } + fclose(fp); +} + +bool Simulator::ReadThresFile(char *file, std::vector<GridNode> *nodes, std::vector<float> *thresVals) { + FloatGrid *grid = NULL; + + grid = ReadFloatTifGrid(file); + + if (!grid) { + WARNING_LOGF("Failed to open threshold file %s", file); + return false; + } + + // We have two options now... Either the grid & the basic grids are the same + // Or they are different! + + if (g_DEM->IsSpatialMatch(grid)) { + INFO_LOGF("Loading exact match threshold grid %s", file); + // The grids are the same! Our life is easy! + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (grid->data[node->y][node->x] != grid->noData) { + thresVals->at(i) = grid->data[node->y][node->x]; + } else { + thresVals->at(i) = 0; + } + } + + } else { + INFO_LOGF("Threshold grids aren't an exact match so guessing! %s", file); + // The grids are different, we must do some resampling fun. + GridLoc pt; + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && grid->data[pt.y][pt.x] != grid->noData) { + thresVals->at(i) = grid->data[pt.y][pt.x]; + } else { + thresVals->at(i) = 0; + } + } + + } + + delete grid; + + return true; +} + +float Simulator::ComputeThresValue(float discharge, float action, float minor, float moderate, float major) { + float result = g_DEM->noData; + if (major == major && discharge >= major) { + result = (discharge-major)/major + 4.0; + } else if (major == major && moderate == moderate && discharge >= moderate) { + result = (discharge-moderate)/(major - moderate) + 3.0; + } else if (moderate == moderate && minor == minor && discharge >= minor) { + result = (discharge-minor)/(moderate-minor) + 2.0; + } else if (minor == minor && action == action && discharge >= action) { + result = (discharge-action)/(minor-action) + 1.0; + } else if (action == action) { + result = discharge/action; + } + + if (!std::isfinite(result) || result > 10.0) { + result = g_DEM->noData; + } + + return result; +} + +float Simulator::ComputeThresValueP(float discharge, float action, float actionSD, float minor, float minorSD, float moderate, float moderateSD, float major, float majorSD) { + float result = g_DEM->noData; + float thres = 0.8; + if (major == major && CalcProb(discharge, major, majorSD) > thres) { + result = CalcProb(discharge, major, majorSD) + 4.0; + } else if (major == major && moderate == moderate && CalcProb(discharge, moderate, moderateSD) > thres) { + result = CalcProb(discharge, major, majorSD) + 3.0; + } else if (moderate == moderate && minor == minor && CalcProb(discharge, minor, minorSD) > thres) { + result = CalcProb(discharge, moderate, moderateSD) + 2.0; + } else if (minor == minor && action == action && CalcProb(discharge, action, actionSD) > thres) { + result = CalcProb(discharge, minor, minorSD) + 1.0; + } else if (action == action) { + result = CalcProb(discharge, action, actionSD); + } + + if (!std::isfinite(result) || result > 10.0) { + result = g_DEM->noData; + } + + return result; +} + +float Simulator::CalcProb(float discharge, float mean, float sd) { + return 0.5f * (1.0 + erf((discharge - mean) / (logf(sd) * sqrtf(2)))); +} + +void Simulator::SimulateDistributed(bool trackPeaks) { + PrecipReader precipReader; + PETReader petReader; + TempReader tempReader; + std::vector<float> currentPrecipSnow; + std::vector<float> *currentPrecip = ¤tPrecipSimu; + char buffer[CONFIG_MAX_LEN*2]; + size_t tsIndex = 0; + bool outputTS = IsOutputTS(); + //NORMAL_LOGF("%s\n", "Got here!3"); + // Peak tracking variables + numYears = 0; + int currentYear = -1; + int indexYear = -1; + + // Initialize TempReader + if (sModel) { + tempReader.ReadDEM(tempSec->GetDEM()); + } else { + tempReader.SetNullDEM(); + } + + std::vector<float> actionVals, minorVals, moderateVals, majorVals; + std::vector<float> actionSDVals, minorSDVals, moderateSDVals, majorSDVals; + bool outputThres = false, outputThresP = false; + + if (((griddedOutputs & OG_THRES) == OG_THRES || (griddedOutputs & OG_MAXTHRES) == OG_MAXTHRES) && task->GetActionGrid() && task->GetMinorGrid() && task->GetModerateGrid() && task->GetMajorGrid()) { + actionVals.resize(nodes.size()); + minorVals.resize(nodes.size()); + moderateVals.resize(nodes.size()); + majorVals.resize(nodes.size()); + if (ReadThresFile(task->GetActionGrid(), &nodes, &actionVals) && ReadThresFile(task->GetMinorGrid(), &nodes, &minorVals) && ReadThresFile(task->GetModerateGrid(), &nodes, &moderateVals) && ReadThresFile(task->GetMajorGrid(), &nodes, &majorVals)) { + outputThres = true; + + if (((griddedOutputs & OG_MAXTHRESP) == OG_MAXTHRESP) && task->GetActionSDGrid() && task->GetMinorSDGrid() && task->GetModerateSDGrid() && task->GetMajorSDGrid()) { + actionSDVals.resize(nodes.size()); + minorSDVals.resize(nodes.size()); + moderateSDVals.resize(nodes.size()); + majorSDVals.resize(nodes.size()); + if (ReadThresFile(task->GetActionSDGrid(), &nodes, &actionSDVals) && ReadThresFile(task->GetMinorSDGrid(), &nodes, &minorSDVals) && ReadThresFile(task->GetModerateSDGrid(), &nodes, &moderateSDVals) && ReadThresFile(task->GetMajorSDGrid(), &nodes, &majorSDVals)) { + outputThresP = true; + for (size_t i = 0; i < currentFF.size(); i++) { + actionSDVals[i] = 3.67 * nodes[i].contribArea; + minorSDVals[i] = 3.67 * nodes[i].contribArea; + moderateSDVals[i] = 3.67 * nodes[i].contribArea; + majorSDVals[i] = 3.67 * nodes[i].contribArea; + + + } + } + + } + + } + + } + + bool savePrecip = false; + std::vector<float> qpeAccum, qpfAccum; + if ((griddedOutputs & OG_PRECIPACCUM) == OG_PRECIPACCUM) { + qpeAccum.resize(nodes.size()); + qpfAccum.resize(nodes.size()); + savePrecip = true; + } + + // Initialize our models + // NORMAL_LOGF("%s\n", "Got here!4"); + wbModel->InitializeModel(&nodes, &fullParamSettings, ¶mGrids); + // NORMAL_LOGF("%s\n", "Got here!5"); + if (rModel) { + rModel->InitializeModel(&nodes, &fullParamSettingsRoute, ¶mGridsRoute); + } + // NORMAL_LOGF("%s\n", "Got here!6"); + if (sModel) { + currentPrecipSnow.resize(currentPrecipSimu.size()); + sModel->InitializeModel(&nodes, &fullParamSettingsSnow, ¶mGridsSnow); + } + if (iModel) { + iModel->InitializeModel(&nodes, &fullParamSettingsInundation, ¶mGridsInundation); + } + if (griddedOutputs != OG_NONE || trackPeaks || outputRP || saveStates) { + gridWriter.Initialize(); + } + if (useStates) { + wbModel->InitializeStates(¤tTime, statePath); + if (rModel) { + rModel->InitializeStates(¤tTime, statePath, ¤tFF, ¤tSF); + } + if (sModel) { + sModel->InitializeStates(¤tTime, statePath); + } + } else { + for (size_t i = 0; i < currentFF.size(); i++) { + currentFF[i] = 0.0; + currentSF[i] = 0.0; + currentSWE[i] = 0.0; + } + } + + // Set up stuff for peak tracking here, if needed + if (trackPeaks) { + numYears = GetNumSimulatedYears(); + INFO_LOGF("Number of years is %f\n", numYears); + + // Allocate storage + peakVals.resize((int)numYears); + for (int i = 0; i < numYears; i++) { + peakVals[i].resize(currentFF.size()); + } + } + + // Hard coded RP counting + std::vector<float> count2, rpGrid, rpMaxGrid, maxGrid; + std::vector<float> SM; + std::vector<float> dailyMaxQ, dailyMinSM, dailyMaxQHour; + count2.resize(currentFF.size()); + rpGrid.resize(currentFF.size()); + rpMaxGrid.resize(currentFF.size()); + maxGrid.resize(currentFF.size()); + SM.resize(currentFF.size()); + + for (size_t i = 0; i < currentFF.size(); i++) { + count2[i] = 0.0; + rpGrid[i] = 0.0; + rpMaxGrid[i] = 0.0; + maxGrid[i] = 0.0; + currentFF[i] = 0.0; + currentSF[i] = 0.0; + currentQ[i] = 0.0; + } + +#if _OPENMP + double timeTotal = 0.0, timeCount = 0.0; +#endif + + // This is the temporal loop for each time step + // Here we load the input forcings & actually run the model + for (currentTime.Increment(timeStep); currentTime <= endTime; currentTime.Increment(timeStep)) { +#if _OPENMP +#ifndef _WIN32 + double beginTime = omp_get_wtime(); +#endif +#endif + currentTimeText.UpdateName(currentTime.GetTM()); +#ifndef _WIN32 + NORMAL_LOGF("%s", currentTimeText.GetName()); +#else + setTimestep(currentTimeText.GetName()); +#endif + + int qpf = 0; + if (!preloadedForcings) { + qpf = LoadForcings(&precipReader, &petReader, &tempReader); + currentPrecip = ¤tPrecipSimu; + } + + float stepHoursReal = timeStep->GetTimeInSec() / 3600.0f; + + if (sModel) { + if (preloadedForcings) { + sModel->SnowBalance((float)currentTime.GetTM()->tm_yday, stepHoursReal, &(currentPrecipCali[tsIndex]), &(currentTempCali[tsIndex]), &(currentPrecipCali[tsIndex]), ¤tSWE); + } else { + sModel->SnowBalance((float)currentTime.GetTM()->tm_yday, stepHoursReal, currentPrecip, ¤tTempSimu, ¤tPrecipSnow, ¤tSWE); + currentPrecip = ¤tPrecipSnow; + } + } + + // Integrate the models for this timestep + if (!preloadedForcings) { + wbModel->WaterBalance(stepHoursReal, currentPrecip, ¤tPETSimu, ¤tFF, ¤tSF, &SM); + } else { + wbModel->WaterBalance(stepHoursReal, &(currentPrecipCali[tsIndex]), &(currentPETCali[tsIndex]), ¤tFF, ¤tSF, &SM); + } + if (outputTS) { + gaugeMap.GaugeAverage(&nodes, ¤tFF, &avgFF); + gaugeMap.GaugeAverage(&nodes, ¤tSF, &avgSF); + } + + if (rModel && wantsDA) { + AssimilateData(); + } + if (rModel) { + double beginTimeR = omp_get_wtime(); + rModel->Route(stepHoursReal, ¤tFF, ¤tSF, ¤tQ); + double endTimeR = omp_get_wtime(); + NORMAL_LOGF(" %f routing sec", endTimeR - beginTimeR); + } else { + for (size_t i = 0; i < currentFF.size(); i++) { + currentFF[i] = 0.0; + currentSF[i] = 0.0; + } + } + if (saveStates && stateTime == currentTime) { + wbModel->SaveStates(¤tTime, statePath, &gridWriter); + if (rModel) { + rModel->SaveStates(¤tTime, statePath, &gridWriter); + } + if (sModel) { + sModel->SaveStates(¤tTime, statePath, &gridWriter); + } + } + + // We only output after the warmup period is over + if (warmEndTime <= currentTime) { + + if (savePrecip) { + for (size_t i = 0; i < currentFF.size(); i++) { + float precip = currentPrecip->at(i) * stepHoursReal; + if (qpf) { + qpfAccum[i] += precip; + } else { + qpeAccum[i] += precip; + } + } + } + + OutputCombinedOutput(); + + if (trackPeaks && currentYear != currentTime.GetTM()->tm_year) { + currentYear = currentTime.GetTM()->tm_year; + indexYear++; + } + + if (outputTS) { + gaugeMap.GaugeAverage(&nodes, &SM, &avgSM); + if (!preloadedForcings) { + gaugeMap.GaugeAverage(&nodes, currentPrecip, &avgPrecip); + gaugeMap.GaugeAverage(&nodes, ¤tPETSimu, &avgPET); + } else { + gaugeMap.GaugeAverage(&nodes, &(currentPrecipCali[tsIndex]), &avgPrecip); + gaugeMap.GaugeAverage(&nodes, &(currentPETCali[tsIndex]), &avgPET); + } + + if (sModel) { + gaugeMap.GaugeAverage(&nodes, ¤tSWE, &avgSWE); + if (!preloadedForcings) { + gaugeMap.GaugeAverage(&nodes, ¤tTempSimu, &avgT); + } else { + gaugeMap.GaugeAverage(&nodes, &(currentTempCali[tsIndex]), &avgT); + } + } + + + // Write the output to file + SaveTSOutput(); + } + + if (trackPeaks) { + for (size_t i = 0; i < currentFF.size(); i++) { + if (currentQ[i] > peakVals[indexYear][i]) { + peakVals[indexYear][i] = currentQ[i]; + } + } + } + + // Hard coded rp counting + for (size_t i = 0; i < currentFF.size(); i++) { + float discharge = currentQ[i]; + if (discharge > maxGrid[i]) { + maxGrid[i] = discharge; + } + if (outputRP) { + rpGrid[i] = GetReturnPeriod(discharge, &(rpData[i])); + if (rpGrid[i] > rpMaxGrid[i]) { + rpMaxGrid[i] = rpGrid[i]; + } + } + } + + /*int month = currentTime.GetTM()->tm_mon; + for (size_t i = 0; i < currentFF.size(); i++) { + if (currentQ[i] > monthlyMaxGrid[month][i]) { + monthlyMaxGrid[month][i] = currentQ[i]; + } + }*/ + + if (griddedOutputs != OG_NONE) { + currentTimeTextOutput.UpdateName(currentTime.GetTM()); + } + + if ((griddedOutputs & OG_Q) == OG_Q) { + sprintf(buffer, "%s/q.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tQ, buffer, false); + } + if ((griddedOutputs & OG_SM) == OG_SM) { + sprintf(buffer, "%s/sm.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, &SM, buffer, false); + } + if (outputRP && ((griddedOutputs & OG_QRP) == OG_QRP)) { + sprintf(buffer, "%s/rp.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, &rpGrid, buffer, false); + } + if ((griddedOutputs & OG_PRECIP) == OG_PRECIP) { + sprintf(buffer, "%s/precip.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tPrecipSimu, buffer, false); + } + if ((griddedOutputs & OG_PET) == OG_PET) { + sprintf(buffer, "%s/pet.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tPETSimu, buffer, false); + } + if (sModel && (griddedOutputs & OG_SWE) == OG_SWE) { + sprintf(buffer, "%s/swe.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tSWE, buffer, false); + } + if (sModel && (griddedOutputs & OG_TEMP) == OG_TEMP) { + sprintf(buffer, "%s/temp.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tTempSimu, buffer, false); + } + if (iModel && (griddedOutputs & OG_DEPTH) == OG_DEPTH) { + iModel->Inundation(¤tQ, ¤tDepth); + sprintf(buffer, "%s/depth.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), iModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tDepth, buffer, false); + } + if ((griddedOutputs & OG_UNITQ) == OG_UNITQ) { + for (size_t i = 0; i < currentQ.size(); i++) { + currentDepth[i] = currentQ[i] / nodes[i].contribArea; + } + sprintf(buffer, "%s/unitq.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tDepth, buffer, false); + } + if (outputThres && (griddedOutputs & OG_THRES) == OG_THRES) { + for (size_t i = 0; i < currentQ.size(); i++) { + currentDepth[i] = ComputeThresValue(currentQ[i], actionVals[i], minorVals[i], moderateVals[i], majorVals[i]); + } + sprintf(buffer, "%s/thres.%s.%s.tif", outputPath, currentTimeTextOutput.GetName(), wbModel->GetName()); + gridWriter.WriteGrid(&nodes, ¤tDepth, buffer, false); + + } + + + } + +#if _OPENMP +#ifndef _WIN32 + double endTime = omp_get_wtime(); + double timeDiff = endTime - beginTime; + NORMAL_LOGF(" %f sec", endTime - beginTime); + timeTotal += timeDiff; + timeCount++; + if (timeCount == 250) { + NORMAL_LOGF(" (%f sec avg)", timeTotal / timeCount); + timeCount = 0.0; + timeTotal = 0.0; + } +#endif +#endif + + if (timeStepLR && !inLR && beginLRTime <= currentTime) { + inLR = true; + timeStep = timeStepLR; + NORMAL_LOGF(" Switching to long range timestep %f hours", timeStepHoursLR); + } + + // All of our status messages are done for this timestep! +#ifndef _WIN32 + NORMAL_LOGF("%s", "\n"); +#endif + tsIndex++; + } + + if (trackPeaks) { + SaveLP3Params(); + } + + tm *ctWE = warmEndTime.GetTM(); + + // Hard coded event counting + if (outputRP && ((griddedOutputs & OG_MAXQRP) == OG_MAXQRP)) { + + sprintf(buffer, "%s/maxrp.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + for (size_t i = 0; i < currentQ.size(); i++) { + float val = floorf(rpMaxGrid[i] + 0.5f); + rpMaxGrid[i] = val; + } + gridWriter.WriteGrid(&nodes, &rpMaxGrid, buffer, false); + + //sprintf(buffer, "%s/qmax.%s.asc", outputPath, model->GetName()); + //gridWriter.WriteGrid(&nodes, &maxGrid, buffer); + } + + if ((griddedOutputs & OG_MAXSM) == OG_MAXSM) { + sprintf(buffer, "%s/maxsm.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + for (size_t i = 0; i < currentQ.size(); i++) { + float val = floorf(SM[i] + 0.5f); + SM[i] = val; + } + gridWriter.WriteGrid(&nodes, &SM, buffer, false); + } + + if ((griddedOutputs & OG_MAXQ) == OG_MAXQ) { + sprintf(buffer, "%s/maxq.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + for (size_t i = 0; i < currentQ.size(); i++) { + float val = floorf(maxGrid[i] * 10.0 + 0.5f) / 10.0f; + maxGrid[i] = val; + } + gridWriter.WriteGrid(&nodes, &maxGrid, buffer, false); + } + + if (sModel && (griddedOutputs & OG_MAXSWE) == OG_MAXSWE) { + sprintf(buffer, "%s/maxswe.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + gridWriter.WriteGrid(&nodes, ¤tSWE, buffer, false); + } + + if ((griddedOutputs & OG_MAXUNITQ) == OG_MAXUNITQ) { + for (size_t i = 0; i < currentQ.size(); i++) { + currentDepth[i] = maxGrid[i] / nodes[i].contribArea; + float val = floorf(currentDepth[i] * 10.0 + 0.5f) / 10.0f; + currentDepth[i] = val; + } + sprintf(buffer, "%s/maxunitq.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + gridWriter.WriteGrid(&nodes, ¤tDepth, buffer, false); + } + + if (outputThres && (griddedOutputs & OG_MAXTHRES) == OG_MAXTHRES) { + for (size_t i = 0; i < currentQ.size(); i++) { + currentDepth[i] = ComputeThresValue(maxGrid[i], actionVals[i], minorVals[i], moderateVals[i], majorVals[i]); + } + sprintf(buffer, "%s/maxthres.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + gridWriter.WriteGrid(&nodes, ¤tDepth, buffer, false); + + } + + if (outputThresP && (griddedOutputs & OG_MAXTHRESP) == OG_MAXTHRESP) { + for (size_t i = 0; i < currentQ.size(); i++) { + currentDepth[i] = ComputeThresValueP(maxGrid[i], actionVals[i], actionSDVals[i], minorVals[i], minorSDVals[i], moderateVals[i], moderateSDVals[i], majorVals[i], majorSDVals[i]); + } + sprintf(buffer, "%s/maxthresp.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + gridWriter.WriteGrid(&nodes, ¤tDepth, buffer, false); + + } + + if (savePrecip) { + sprintf(buffer, "%s/qpeaccum.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + gridWriter.WriteGrid(&nodes, &qpeAccum, buffer, false); + sprintf(buffer, "%s/qpfaccum.%04i%02i%02i.%02i%02i%02i.tif", outputPath, ctWE->tm_year + 1900, ctWE->tm_mon + 1, ctWE->tm_mday, ctWE->tm_hour, ctWE->tm_min, ctWE->tm_sec); + gridWriter.WriteGrid(&nodes, &qpfAccum, buffer, false); + } + +} + +void Simulator::SimulateLumped() { + PrecipReader precipReader; + PETReader petReader; + char buffer[CONFIG_MAX_LEN*2]; + size_t tsIndex = 0; + + std::vector<float> SM; + SM.resize(currentFF.size()); + + + // Initialize our model + wbModel->InitializeModel(&lumpedNodes, &fullParamSettings, ¶mGrids); + + // This is the temporal loop for each time step + // Here we load the input forcings & actually run the model + for (currentTime.Increment(timeStep); currentTime <= endTime; currentTime.Increment(timeStep)) { + currentTimeText.UpdateName(currentTime.GetTM()); + printf("%s", currentTimeText.GetName()); + + if (!preloadedForcings) { + + if (currentTimePrecip < currentTime) { + currentTimePrecip.Increment(timeStepPrecip); + } + + if (currentTimePET < currentTime) { + currentTimePET.Increment(timeStepPET); + } + + precipFile->UpdateName(currentTimePrecip.GetTM()); + petFile->UpdateName(currentTimePET.GetTM()); + + sprintf(buffer, "%s/%s", precipSec->GetLoc(), precipFile->GetName()); + if (!precipReader.Read(buffer, precipSec->GetType(), &nodes, ¤tPrecipSimu, precipConvert)) { + printf(" Missing precip file(%s)... Assuming zeros.", buffer); + } + + sprintf(buffer, "%s/%s", petSec->GetLoc(), petFile->GetName()); + if (!petReader.Read(buffer, petSec->GetType(), &nodes, ¤tPETSimu, petConvert, petSec->IsTemperature(), (float)currentTime.GetTM()->tm_yday)) { + printf(" Missing PET file(%s)... Assuming zeros.", buffer); + } + + } + + + if (!preloadedForcings) { + gaugeMap.GaugeAverage(&nodes, ¤tPrecipSimu, &avgPrecip); + gaugeMap.GaugeAverage(&nodes, ¤tPETSimu, &avgPET); + + wbModel->WaterBalance(timeStepHours, &avgPrecip, &avgPET, ¤tFF, ¤tSF, &SM); + } else { + wbModel->WaterBalance(timeStepHours, &(currentPrecipCali[tsIndex]), &(currentPETCali[tsIndex]), ¤tFF, ¤tSF, &SM); + } + // We only output after the warmup period is over + if (warmEndTime <= currentTime) { + + // Write the output to file + for (size_t i = 0; i < gauges->size(); i++) { + GaugeConfigSection *gauge = gauges->at(i); + if (gaugeOutputs[i]) { + float discharge = (currentFF[gauge->GetGridNodeIndex()] + currentSF[gauge->GetGridNodeIndex()]) * nodes[gauge->GetGridNodeIndex()].area / 3.6; + if (!preloadedForcings) { + fprintf(gaugeOutputs[i], "%s,%.2f,%.2f,%.2f,%.2f\n", currentTimeText.GetName(), discharge, gauge->GetObserved(¤tTime), avgPrecip[i], avgPET[i]); + } else { + fprintf(gaugeOutputs[i], "%s,%.2f,%.2f,%.2f,%.2f\n", currentTimeText.GetName(), discharge, gauge->GetObserved(¤tTime), currentPrecipCali[tsIndex].at(i), currentPETCali[tsIndex].at(i)); + } + } + } + } + + // All of our status messages are done for this timestep! + printf("%s", "\n"); + tsIndex++; + } + +} + +void Simulator::PreloadForcings(char *file, bool cali) { + + PrecipReader precipReader; + PETReader petReader; + TempReader tempReader; + char buffer[CONFIG_MAX_LEN*2]; + std::vector<float> readVec; + size_t tsIndex = 0, tsIndexWarm = 0; + + if (LoadSavedForcings(file, cali)) { + // We found a saved forcing file that we loaded, woo! + return; + } + + // Initialize TempReader + if (sModel) { + tempReader.ReadDEM(tempSec->GetDEM()); + } else { + tempReader.SetNullDEM(); + } + + currentTime = beginTime; + for (currentTime.Increment(timeStep); currentTime <= endTime; currentTime.Increment(timeStep)) { + if (currentTimePrecip < currentTime) { + currentTimePrecip.Increment(timeStepPrecip); + } + + if (currentTimePET < currentTime) { + currentTimePET.Increment(timeStepPET); + } + + if (sModel && currentTimeTemp < currentTime) { + currentTimeTemp.Increment(timeStepTemp); + } + + // CONT + + precipFile->UpdateName(currentTimePrecip.GetTM()); + petFile->UpdateName(currentTimePET.GetTM()); + if (sModel) { + tempFile->UpdateName(currentTimeTemp.GetTM()); + } + + + std::vector<float> *precipVec = &(currentPrecipCali[tsIndex]); + std::vector<float> *petVec = &(currentPETCali[tsIndex]); + std::vector<float> *tempVec = NULL; + if (sModel) { + tempVec = &(currentTempCali[tsIndex]); + } + if (!wbModel->IsLumped()) { + precipVec->resize(nodes.size()); + petVec->resize(nodes.size()); + if (sModel) { + tempVec->resize(nodes.size()); + } + } else { + precipVec->resize(gauges->size()); + petVec->resize(gauges->size()); + if (sModel) { + tempVec->resize(gauges->size()); + } + } + + if (wbModel->IsLumped()) { + // We are a lumped model... + // therefore only care about averages! + // + readVec.resize(nodes.size()); + std::vector<float> *vec, *vecPrev; + + sprintf(buffer, "%s/%s", precipSec->GetLoc(), precipFile->GetName()); + vec = &(currentPrecipCali[tsIndex]); + if (tsIndex > 0) { + vec = &(currentPrecipCali[tsIndex-1]); + } else { + vecPrev = NULL; + } + if (!precipReader.Read(buffer, precipSec->GetType(), &nodes, &readVec, precipConvert, vecPrev)) { + NORMAL_LOGF("Missing precip file(%s)... Assuming zeros.\n", buffer); + } + gaugeMap.GaugeAverage(&nodes, &readVec, vec); + + sprintf(buffer, "%s/%s", petSec->GetLoc(), petFile->GetName()); + vec = &(currentPETCali[tsIndex]); + if (tsIndex > 0) { + vec = &(currentPETCali[tsIndex-1]); + } else { + vecPrev = NULL; + } + if (!petReader.Read(buffer, petSec->GetType(), &nodes, &readVec, petConvert, petSec->IsTemperature(), currentTime.GetTM()->tm_yday, vecPrev)) { + NORMAL_LOGF("Missing PET file(%s)... Assuming zeros.\n", buffer); + } + gaugeMap.GaugeAverage(&nodes, &readVec, vec); + } else { + std::vector<float> *vec, *vecPrev; + + sprintf(buffer, "%s/%s", precipSec->GetLoc(), precipFile->GetName()); + vec = &(currentPrecipCali[tsIndex]); + if (tsIndex > 0) { + vecPrev = &(currentPrecipCali[tsIndex-1]); + } else { + vecPrev = NULL; + } + if (!precipReader.Read(buffer, precipSec->GetType(), &nodes, vec, precipConvert, vecPrev)) { + NORMAL_LOGF("Missing precip file(%s)... Assuming zeros.\n", buffer); + } + + sprintf(buffer, "%s/%s", petSec->GetLoc(), petFile->GetName()); + vec = &(currentPETCali[tsIndex]); + if (tsIndex > 0) { + vecPrev = &(currentPETCali[tsIndex-1]); + } else { + vecPrev = NULL; + } + if (!petReader.Read(buffer, petSec->GetType(), &nodes, vec, petConvert, petSec->IsTemperature(), currentTime.GetTM()->tm_yday, vecPrev)) { + NORMAL_LOGF("Missing PET file(%s)... Assuming zeros.\n", buffer); + } + + if (sModel) { + sprintf(buffer, "%s/%s", tempSec->GetLoc(), tempFile->GetName()); + vec = &(currentTempCali[tsIndex]); + if (tsIndex > 0) { + vecPrev = &(currentTempCali[tsIndex-1]); + } else { + vecPrev = NULL; + } + if (!tempReader.Read(buffer, tempSec->GetType(), &nodes, vec, vecPrev)) { + NORMAL_LOGF("Missing Temp file(%s)... Assuming zeros.\n", buffer); + } + } + + } + + if (cali && warmEndTime <= currentTime) { + obsQ[tsIndexWarm] = caliGauge->GetObserved(¤tTime); + tsIndexWarm++; + } + + tsIndex++; + } + + SaveForcings(file); +} + +bool Simulator::LoadSavedForcings(char *file, bool cali) { + gzFile filep = gzopen(file, "r"); + if (filep == NULL) { + WARNING_LOGF("Failed to load preload file %s", file); + return false; + } + time_t temp; + if (gzread(filep, &temp, sizeof(time_t)) != sizeof(time_t) || !(temp == beginTime.currentTimeSec)) { + gzclose(filep); + WARNING_LOGF("Wrong beginning time for preload file %s, not loaded", file); + return false; + } + if (gzread(filep, &temp, sizeof(time_t)) != sizeof(time_t) || !(temp == endTime.currentTimeSec)) { + gzclose(filep); + WARNING_LOGF("Wrong ending time for preload file %s, not loaded (%lu %lu)", file, temp, endTime.currentTimeSec); + return false; + } + size_t steps; + if (gzread(filep, &steps, sizeof(totalTimeSteps)) != sizeof(totalTimeSteps) || steps != totalTimeSteps) { + gzclose(filep); + WARNING_LOGF("Wrong number of timesteps for preload file %s, not loaded (%lu %lu)", file, steps, totalTimeSteps); + return false; + } + + INFO_LOGF("Loading saved binary forcing file, %s!", file); + + int numDataPoints; + if (!wbModel->IsLumped()) { + numDataPoints = nodes.size(); + } else { + numDataPoints = gauges->size(); + } + for (size_t tsIndex = 0; tsIndex < totalTimeSteps; tsIndex++) { + std::vector<float> *precipVec = &(currentPrecipCali[tsIndex]); + std::vector<float> *petVec = &(currentPETCali[tsIndex]); + std::vector<float> *tempVec = NULL; + precipVec->resize(numDataPoints); + petVec->resize(numDataPoints); + gzread(filep, &(precipVec->at(0)), sizeof(float) * numDataPoints); + gzread(filep, &(petVec->at(0)), sizeof(float) * numDataPoints); + if (sModel) { + tempVec = &(currentTempCali[tsIndex]); + tempVec->resize(numDataPoints); + gzread(filep, &(tempVec->at(0)), sizeof(float) * numDataPoints); + } + } + + gzclose(filep); + + if (!cali) { + return true; + } + + size_t tsIndexWarm = 0; + currentTime = beginTime; + for (currentTime.Increment(timeStep); currentTime <= endTime; currentTime.Increment(timeStep)) { + if (warmEndTime <= currentTime) { + obsQ[tsIndexWarm] = caliGauge->GetObserved(¤tTime); + tsIndexWarm++; + } + } + return true; +} + +void Simulator::SaveForcings(char *file) { + gzFile filep = gzopen(file, "w9"); + gzwrite(filep, &(beginTime.currentTimeSec), sizeof(time_t)); + gzwrite(filep, &(endTime.currentTimeSec), sizeof(time_t)); + gzwrite(filep, &totalTimeSteps, sizeof(totalTimeSteps)); + int numDataPoints; + if (!wbModel->IsLumped()) { + numDataPoints = nodes.size(); + } else { + numDataPoints = gauges->size(); + } + for (size_t tsIndex = 0; tsIndex < totalTimeSteps; tsIndex++) { + std::vector<float> *precipVec = &(currentPrecipCali[tsIndex]); + std::vector<float> *petVec = &(currentPETCali[tsIndex]); + gzwrite(filep, &(precipVec->at(0)), sizeof(float)*numDataPoints); + gzwrite(filep, &(petVec->at(0)), sizeof(float)*numDataPoints); + if (sModel) { + std::vector<float> *tempVec = &(currentTempCali[tsIndex]); + gzwrite(filep, &(tempVec->at(0)), sizeof(float)*numDataPoints); + } + } + gzclose(filep); +} + +float Simulator::SimulateForCali(float *testParams) { + + WaterBalanceModel *runModel; + RoutingModel *runRoutingModel; + SnowModel *runSnowModel; + std::vector<float> currentFFCali, currentSFCali, currentQCali, simQCali, SMCali, currentSWECali, currentPrecipSnow; + TimeVar currentTimeCali; + std::map<GaugeConfigSection *, float *> *currentWBParamSettings; + std::map<GaugeConfigSection *, float *> *currentRParamSettings; + std::map<GaugeConfigSection *, float *> *currentSParamSettings; + float *currentWBParams, *currentRParams, *currentSParams; +#if _OPENMP + int thread = omp_get_thread_num(); + runModel = caliWBModels[thread]; + runRoutingModel = caliRModels[thread]; + runSnowModel = caliSModels[thread]; + currentWBParamSettings = &(caliWBFullParamSettings[thread]); + currentWBParams = caliWBCurrentParams[thread]; + currentRParamSettings = &(caliRFullParamSettings[thread]); + currentRParams = caliRCurrentParams[thread]; + currentSParamSettings = &(caliSFullParamSettings[thread]); + currentSParams = caliSCurrentParams[thread]; +#else + runModel = wbModel; + runRoutingModel = rModel; + runSnowModel = sModel; + currentWBParamSettings = &fullParamSettings; + currentRParamSettings = &fullParamSettingsRoute; + currentSParamSettings = &fullParamSettingsSnow; + currentWBParams = caliWBParams; + currentRParams = caliRParams; + currentSParams = caliSParams; +#endif + + memcpy(currentWBParams, testParams, sizeof(float)*numWBParams); + memcpy(currentRParams, testParams+numWBParams, sizeof(float)*numRParams); + memcpy(currentSParams, testParams+numWBParams+numRParams, sizeof(float)*numSParams); + + // Initialize our model + if (!runModel->IsLumped()) { + runModel->InitializeModel(&nodes, currentWBParamSettings, ¶mGrids); + } else { + runModel->InitializeModel(&lumpedNodes, currentWBParamSettings, ¶mGrids); + } + + runRoutingModel->InitializeModel(&nodes, currentRParamSettings, ¶mGridsRoute); + + if (runSnowModel) { + runSnowModel->InitializeModel(&nodes, currentSParamSettings, ¶mGridsSnow); + } + + + currentFFCali.resize(currentFF.size()); + currentSFCali.resize(currentFF.size()); + currentQCali.resize(currentFF.size()); + currentSWECali.resize(currentFF.size()); + currentPrecipSnow.resize(currentFF.size()); + SMCali.resize(currentFF.size()); + simQCali.resize(simQ.size()); + avgPrecip.resize(gauges->size()); + avgPET.resize(gauges->size()); + + // This is the temporal loop for each time step + // Here we actually run the model + size_t tsIndex = 0, tsIndexWarm = 0; + currentTimeCali = beginTime; + + for (currentTimeCali.Increment(timeStep); currentTimeCali <= endTime; currentTimeCali.Increment(timeStep)) { + + std::vector<float> *precipVec = &(currentPrecipCali[tsIndex]); + std::vector<float> *petVec = &(currentPETCali[tsIndex]); + + if (runSnowModel) { + std::vector<float> *tempVec = &(currentTempCali[tsIndex]); + runSnowModel->SnowBalance((float)currentTimeCali.GetTM()->tm_yday, timeStepHours, precipVec, tempVec, ¤tPrecipSnow, ¤tSWECali); + precipVec = ¤tPrecipSnow; + } + /*if (tsIndex == 0) { + gaugeMap.GaugeAverage(&nodes, precipVec, &avgPrecip); + gaugeMap.GaugeAverage(&nodes, petVec, &avgPET); + printf("%f %f\n", precipVec->at(300), petVec->at(300)); + }*/ + runModel->WaterBalance(timeStepHours, precipVec, petVec, ¤tFFCali, ¤tSFCali, &SMCali); + + runRoutingModel->Route(timeStepHours, ¤tFFCali, ¤tSFCali, ¤tQCali); + + if (warmEndTime <= currentTimeCali) { + simQCali[tsIndexWarm] = currentQCali[caliGauge->GetGridNodeIndex()]; + tsIndexWarm++; + } + + tsIndex++; + } + float skill = CalcObjFunc(&obsQ, &simQCali, objectiveFunc); +#if _OPENMP + //printf("%i: %f %f\n", thread, skill, rP[0]); + /*if (skill < -2000.0) { + for (unsigned int i = 0; i < tsIndexWarm; i++) { + printf("dump %i: %f %f\n", thread, obsQ[i], simQCali[i]); + } + }*/ +#else + //printf("%f\n", skill); +#endif + return skill; + //return CalcObjFunc(&obsQ, &simQCali, objectiveFunc); +} + +float *Simulator::SimulateForCaliTS(float *testParams) { + + WaterBalanceModel *runModel; + std::vector<float> currentFFCali, currentSFCali, SMCali; + float *simQCali; + TimeVar currentTimeCali; + std::map<GaugeConfigSection *, float *> *currentParamSettings; + float *currentParams; +#if 0 //def _OPENMP + int thread = omp_get_thread_num(); + runModel = caliModels[thread]; + currentParamSettings = &(caliFullParamSettings[thread]); + currentParams = caliCurrentParams[thread]; +#else + runModel = wbModel; + currentParamSettings = &fullParamSettings; + currentParams = caliWBParams; +#endif + + memcpy(currentParams, testParams, sizeof(float)*numWBParams); + + // Initialize our model + if (!runModel->IsLumped()) { + runModel->InitializeModel(&nodes, currentParamSettings, ¶mGrids); + } else { + runModel->InitializeModel(&lumpedNodes, currentParamSettings, ¶mGrids); + } + + currentFFCali.resize(currentFF.size()); + SMCali.resize(currentFF.size()); + simQCali = new float[simQ.size()]; + + // This is the temporal loop for each time step + // Here we actually run the model + size_t tsIndex = 0, tsIndexWarm = 0; + currentTimeCali = beginTime; + + for (currentTimeCali.Increment(timeStep); currentTimeCali <= endTime; currentTimeCali.Increment(timeStep)) { + + std::vector<float> *precipVec = &(currentPrecipCali[tsIndex]); + std::vector<float> *petVec = &(currentPETCali[tsIndex]); + + runModel->WaterBalance(timeStepHours, precipVec, petVec, ¤tFFCali, ¤tSFCali, &SMCali); + if (warmEndTime <= currentTimeCali) { + if (!runModel->IsLumped()) { + simQCali[tsIndexWarm] = currentFFCali[caliGauge->GetGridNodeIndex()]; + } else { + simQCali[tsIndexWarm] = currentFFCali[caliGaugeIndex]; + } + tsIndexWarm++; + } + + tsIndex++; + } + + return simQCali; +} + +float *Simulator::GetObsTS() { + float *obsData = new float[obsQ.size()]; + + for (size_t i = 0; i < obsQ.size(); i++) { + obsData[i] = obsQ[i]; + } + + return obsData; +} + +bool Simulator::InitializeGridParams(TaskConfigSection *task) { + int numParams = numModelParams[task->GetModel()]; + std::vector<std::string> *vecGrids = task->GetParamsSec()->GetParamGrids(); + + paramGrids.resize(numParams); + + for (int i = 0; i < numParams; i++) { + std::string *file = &(vecGrids->at(i)); + if (file->length() == 0) { + paramGrids[i] = NULL; + } else { + paramGrids[i] = ReadFloatTifGrid(file->c_str()); + if (!paramGrids[i]) { + ERROR_LOGF("Failed to load water balance parameter grid %s\n", file->c_str()); + return false; + } + } + } + + if (task->GetRouting() != ROUTE_QTY) { + int numRParams = numRouteParams[task->GetRouting()]; + std::vector<std::string> *vecRouteGrids = task->GetRoutingParamsSec()->GetParamGrids(); + + paramGridsRoute.resize(numRParams); + + for (int i = 0; i < numRParams; i++) { + std::string *file = &(vecRouteGrids->at(i)); + if (file->length() == 0) { + paramGridsRoute[i] = NULL; + } else { + paramGridsRoute[i] = ReadFloatTifGrid(file->c_str()); + if (!paramGridsRoute[i]) { + ERROR_LOGF("Failed to load routing parameter grid %s\n", file->c_str()); + return false; + } + } + } + } + + if (task->GetSnow() != SNOW_QTY) { + int numSParams = numSnowParams[task->GetSnow()]; + std::vector<std::string> *vecSnowGrids = task->GetSnowParamsSec()->GetParamGrids(); + + paramGridsSnow.resize(numSParams); + + for (int i = 0; i < numSParams; i++) { + std::string *file = &(vecSnowGrids->at(i)); + if (file->length() == 0) { + paramGridsSnow[i] = NULL; + } else { + paramGridsSnow[i] = ReadFloatTifGrid(file->c_str()); + if (!paramGridsSnow[i]) { + ERROR_LOGF("Failed to load snow parameter grid %s\n", file->c_str()); + return false; + } + } + } + + } + + if (task->GetInundation() != INUNDATION_QTY) { + int numIParams = numInundationParams[task->GetInundation()]; + std::vector<std::string> *vecInundationGrids = task->GetInundationParamsSec()->GetParamGrids(); + + paramGridsInundation.resize(numIParams); + + for (int i = 0; i < numIParams; i++) { + std::string *file = &(vecInundationGrids->at(i)); + if (file->length() == 0) { + paramGridsInundation[i] = NULL; + } else { + paramGridsInundation[i] = ReadFloatTifGrid(file->c_str()); + if (!paramGridsInundation[i]) { + ERROR_LOGF("Failed to load inundation parameter grid %s\n", file->c_str()); + return false; + } + } + } + + } + + return true; + +} diff --git a/src/Simulator.h b/src/Simulator.h new file mode 100755 index 0000000..d23f100 --- /dev/null +++ b/src/Simulator.h @@ -0,0 +1,119 @@ +#ifndef SIMULATOR_H +#define SIMULATOR_H + +#include "GaugeMap.h" +#include "GridNode.h" +#include "GaugeConfigSection.h" +#include "Model.h" +#include "ModelBase.h" +#include "PETConfigSection.h" +#include "PrecipConfigSection.h" +#include "TempConfigSection.h" +#include "TaskConfigSection.h" +#include "RPSkewness.h" +#include "PrecipReader.h" +#include "PETReader.h" +#include "TempReader.h" + +class Simulator { +public: + bool Initialize(TaskConfigSection *taskN); + void PreloadForcings(char *file, bool cali); + bool LoadSavedForcings(char *file, bool cali); + void SaveForcings(char *file); + + void CleanUp(); + void BasinAvg(); + void Simulate(bool trackPeaks = false); + float SimulateForCali(float *testParams); + float *SimulateForCaliTS(float *testParams); + float *GetObsTS(); + size_t GetNumSteps() { return totalTimeStepsOutsideWarm; } + +private: + bool InitializeBasic(TaskConfigSection *task); + bool InitializeSimu(TaskConfigSection *task); + bool InitializeCali(TaskConfigSection *task); + bool InitializeGridParams(TaskConfigSection *task); + + void SimulateDistributed(bool trackPeaks); + void SimulateLumped(); + + float GetNumSimulatedYears(); + int LoadForcings(PrecipReader *precipReader, PETReader *petReader, TempReader *tempReader); + void SaveLP3Params(); + void SaveTSOutput(); + bool IsOutputTS(); + void LoadDAFile(TaskConfigSection *task); + void AssimilateData(); + void OutputCombinedOutput(); + + bool ReadThresFile(char *file, std::vector<GridNode> *nodes, std::vector<float> *thresVals); + float ComputeThresValue(float discharge, float action, float minor, float moderate, float major); + float ComputeThresValueP(float discharge, float action, float actionSD, float minor, float minorSD, float moderate, float moderateSD, float major, float majorSD); + float CalcProb(float discharge, float mean, float sd); + + // These guys are the basic variables + TaskConfigSection *task; + GridNodeVec nodes; + GridNodeVec lumpedNodes; + WaterBalanceModel *wbModel; + RoutingModel *rModel; + SnowModel *sModel; + InundationModel *iModel; + GaugeMap gaugeMap; + PrecipConfigSection *precipSec, *qpfSec; + PETConfigSection *petSec; + TempConfigSection *tempSec, *tempFSec; + std::vector<GaugeConfigSection *> *gauges; + std::map<GaugeConfigSection *, float *> fullParamSettings, *paramSettings; + std::map<GaugeConfigSection *, float *> fullParamSettingsRoute, *paramSettingsRoute; + std::map<GaugeConfigSection *, float *> fullParamSettingsSnow, *paramSettingsSnow; + std::map<GaugeConfigSection *, float *> fullParamSettingsInundation, *paramSettingsInundation; + TimeUnit *timeStep, *timeStepSR, *timeStepLR, *timeStepPrecip, *timeStepQPF, *timeStepPET, *timeStepTemp, *timeStepTempF; + float precipConvert, qpfConvert, petConvert, timeStepHours, timeStepHoursLR; + TimeVar currentTime, currentTimePrecip, currentTimeQPF, currentTimePET, currentTimeTemp, currentTimeTempF, beginTime, endTime, warmEndTime, beginLRTime; + DatedName *precipFile, *qpfFile, *petFile, *tempFile, *tempFFile, currentTimeText, currentTimeTextOutput, currentDayTextOutput; + std::vector<float> currentFF, currentSF, currentQ, avgPrecip, avgPET, avgSWE, currentSWE, avgT, avgSM, avgFF, avgSF, currentDepth; + std::vector<FloatGrid *> paramGrids, paramGridsRoute, paramGridsSnow, paramGridsInundation; + bool hasQPF, hasTempF, wantsDA; + bool inLR; + std::vector<bool> gaugesUsed; + + // This is for simulations only + std::vector<float> currentPrecipSimu, currentPETSimu, currentTempSimu; + std::vector<FILE *> gaugeOutputs; + int griddedOutputs; + bool outputRP; + bool useStates, saveStates; + bool preloadedForcings; + std::vector<RPData> rpData; + char *outputPath; + char *statePath; + TimeVar stateTime; + std::vector<std::vector<float> > peakVals; + GridWriterFull gridWriter; + float numYears; + + // This is for calibrations only + std::vector<std::vector<float> > currentPrecipCali, currentPETCali, currentTempCali; + std::vector<float> obsQ, simQ; + CaliParamConfigSection *caliParamSec; + RoutingCaliParamConfigSection *routingCaliParamSec; + SnowCaliParamConfigSection *snowCaliParamSec; + OBJECTIVES objectiveFunc; + GaugeConfigSection *caliGauge; + float *caliWBParams; + float *caliRParams; + float *caliSParams; + size_t totalTimeSteps, totalTimeStepsOutsideWarm; + int numWBParams, numRParams, numSParams; + int caliGaugeIndex; + std::vector<WaterBalanceModel *> caliWBModels; + std::vector<RoutingModel *> caliRModels; + std::vector<SnowModel *> caliSModels; + std::vector<float *> caliWBCurrentParams, caliRCurrentParams, caliSCurrentParams; + std::vector<std::map<GaugeConfigSection *, float *> > caliWBFullParamSettings, caliRFullParamSettings, caliSFullParamSettings; +}; + +#endif diff --git a/src/Snow17Model.cpp b/src/Snow17Model.cpp new file mode 100755 index 0000000..a45dada --- /dev/null +++ b/src/Snow17Model.cpp @@ -0,0 +1,333 @@ +#include <cstdio> +#include <cstring> +#include <cmath> +#include "DatedName.h" +#include "Snow17Model.h" + +static const char *stateStrings[] = { + "ati", + "wq", + "wi", + "deficit", +}; + +Snow17Model::Snow17Model() { + +} + +Snow17Model::~Snow17Model() { + +} + +bool Snow17Model::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (snowNodes.size() != nodes->size()) { + snowNodes.resize(nodes->size()); + } + + // Fill in modelIndex in the gridNodes + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + node->modelIndex = i; + float elevation = g_DEM->data[node->y][node->x] / 100.0; + snowNodes[i].P_atm = 33.86 * (29.9 - (0.335 * elevation) + (0.00022 * (powf(elevation,2.4)))); + for (int p = 0; p < STATE_SNOW17_QTY; p++) { + snowNodes[i].states[p] = 0.0; + } + //snowNodes[i].states[STATE_SNOW17_ATI] = 0.0; + //snowNodes[i].states[STATE_SNOW17_WI] = 0.0; + //snowNodes[i].states[STATE_SNOW17_WQ] = 0.0; + //snowNodes[i].states[STATE_SNOW17_DEFICIT] = 0.0; + } + + InitializeParameters(paramSettings, paramGrids); + + return true; +} + +void Snow17Model::InitializeStates(TimeVar *beginTime, char *statePath) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(beginTime->GetTM()); + + char buffer[255]; + for (int p = 0; p < STATE_SNOW17_QTY; p++) { + sprintf(buffer, "%s/snow17_%s_%s.tif", statePath, stateStrings[p], timeStr.GetName()); + + FloatGrid *sGrid = ReadFloatTifGrid(buffer); + if (sGrid) { + printf("Using Snow-17 %s State Grid %s\n", stateStrings[p], buffer); + if (g_DEM->IsSpatialMatch(sGrid)) { + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &nodes->at(i); + Snow17GridNode *cNode = &(snowNodes[i]); + if (sGrid->data[node->y][node->x] != sGrid->noData) { + cNode->states[p] = sGrid->data[node->y][node->x]; + } + } + } else { + GridLoc pt; + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + Snow17GridNode *cNode = &(snowNodes[i]); + if (sGrid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && sGrid->data[pt.y][pt.x] != sGrid->noData) { + cNode->states[p] = sGrid->data[pt.y][pt.x]; + } + } + } + delete sGrid; + } else { + printf("Snow-17 %s State Grid %s not found!\n", stateStrings[p], buffer); + } + } +} + +void Snow17Model::SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter) { + DatedName timeStr; + timeStr.SetNameStr("YYYYMMDD_HHUU"); + timeStr.ProcessNameLoose(NULL); + timeStr.UpdateName(currentTime->GetTM()); + + std::vector<float> dataVals; + dataVals.resize(nodes->size()); + + char buffer[255]; + for (int p = 0; p < STATE_SNOW17_QTY; p++) { + sprintf(buffer, "%s/snow17_%s_%s.tif", statePath, stateStrings[p], timeStr.GetName()); + for (size_t i = 0; i < nodes->size(); i++) { + Snow17GridNode *cNode = &(snowNodes[i]); + dataVals[i] = cNode->states[p]; + } + gridWriter->WriteGrid(nodes, &dataVals, buffer, false); + } + +} + +bool Snow17Model::SnowBalance(float jday, float stepHours, std::vector<float> *precip, std::vector<float> *temp, std::vector<float> *melt, std::vector<float> *swe) { + + size_t numNodes = nodes->size(); + + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + Snow17GridNode *cNode = &(snowNodes[i]); + SnowBalanceInt(node, cNode, stepHours, jday, precip->at(i), temp->at(i), &(melt->at(i)), &(swe->at(i))); + //soilMoisture->at(i) = cNode->soilMoisture * 100.0 / cNode->params[PARAM_CREST_WM]; + } + + return true; +} + +void Snow17Model::SnowBalanceInt(GridNode *node, Snow17GridNode *cNode, float stepHours, float jday, float precipIn, float tempIn, float *melt, float *swe) { + + float stefan = 6.12e-10; + float PXTEMP = 1; // Temperature of rainfall (Deg C) + float TIPM_dtt = 1.0 - (powf(1.0 - cNode->params[PARAM_SNOW17_TIPM], stepHours/6)); + + float precip = precipIn * stepHours; // precipIn is mm/hr, precip is mm + + float Sv = (0.5*sinf((jday-81 * 2 * M_PI)/366.0)) + 0.5; // seasonal variation + float mf = (stepHours/6) * ((Sv * (cNode->params[PARAM_SNOW17_MFMAX] - cNode->params[PARAM_SNOW17_MFMIN])) + cNode->params[PARAM_SNOW17_MFMIN]); // non-rain melt factor, seasonally varying + + // Snow Accumulation + + float fracsnow = 0.0; + float fracrain = 1.0; + + if (tempIn < PXTEMP) { + fracrain = 0.0; + fracsnow = 1.0; + } + + float Pn = precip * fracsnow * cNode->params[PARAM_SNOW17_SCF]; // water equivalent of new snowfall (mm) + cNode->states[STATE_SNOW17_WI] += Pn; // W_i = accumulated water equivalent of the ice portion of the snow cover (mm) + float E = 0; + float RAIN = fracrain * precip; // amount of precip (mm) that is rain during this time step + + + // Temperature and Heat Deficit from new Snow + + float T_snow_new = 0.0; + float delta_HD_snow = 0.0; + float T_rain = tempIn; + + if (tempIn < 0.0) { + T_snow_new = tempIn; + delta_HD_snow = - (T_snow_new*Pn)/(80.0/0.5); // delta_HD_snow = change in the heat deficit due to snowfall (mm) + T_rain = PXTEMP; + } + + // Antecedent temperature Index + + if (Pn > (1.5 * stepHours)) { + cNode->states[STATE_SNOW17_ATI] = T_snow_new; + } else { + cNode->states[STATE_SNOW17_ATI] = cNode->states[STATE_SNOW17_ATI] + TIPM_dtt * (tempIn - cNode->states[STATE_SNOW17_ATI]); // Antecedent temperature index + } + + if (cNode->states[STATE_SNOW17_ATI] > 0) { + cNode->states[STATE_SNOW17_ATI] = 0; + } + + // Heat Exchange when no Surface Melt + + + float delta_HD_T = cNode->params[PARAM_SNOW17_NMF] * (stepHours/6.0) * (mf / cNode->params[PARAM_SNOW17_MFMAX]) * (cNode->states[STATE_SNOW17_ATI] - T_snow_new); // delta_HD_T = change in heat deficit due to a temperature gradient (mm) + + + // Rain-on-Snow Melt + float M_RoS = 0.0; + float e_sat = 2.7489 * 100000000.0 * expf((-4278.63/(tempIn+242.792))); // saturated vapor pressure at T_air_meanC (mb) + if (RAIN > (0.25 * stepHours)) { //1.5 mm/ 6 hrs + //Melt (mm) during rain-on-snow periods is: + float M_RoS1 = fmaxf(stefan * stepHours * (powf(tempIn+273.0, 4.0) - powf(273.0, 4.0)), 0.0); + float M_RoS2 = fmaxf((0.0125 * RAIN * T_rain), 0.0); + float M_RoS3 = fmaxf((8.5 * cNode->params[PARAM_SNOW17_UADJ] * (stepHours/6) * (((0.9 * e_sat) - 6.11) + (0.00057 * cNode->P_atm * tempIn))), 0.0); + M_RoS = M_RoS1 + M_RoS2 + M_RoS3; + } + + + // Non-Rain Melt + float M_NR = 0.0; + if (RAIN <= (0.25 * stepHours) && (tempIn > cNode->params[PARAM_SNOW17_MBASE])) { + //Melt during non-rain periods is: + M_NR = (mf * (tempIn - cNode->params[PARAM_SNOW17_MBASE])) + (0.0125 * RAIN * T_rain); + } + + + // Ripeness of the snow cover + + float Melt = M_RoS + M_NR; + + if (Melt < 0.0) { + Melt = 0.0; + } + + if (Melt < cNode->states[STATE_SNOW17_WI]) { + cNode->states[STATE_SNOW17_WI] -= Melt; + } else { + Melt = cNode->states[STATE_SNOW17_WI] + cNode->states[STATE_SNOW17_WQ]; + cNode->states[STATE_SNOW17_WI] = 0; + } + + float Qw = Melt + RAIN; // Qw = liquid water available melted/rained at the snow surface (mm) + float W_qx = cNode->params[PARAM_SNOW17_PLWHC] * cNode->states[STATE_SNOW17_WI]; // W_qx = liquid water capacity (mm) + cNode->states[STATE_SNOW17_DEFICIT] = cNode->states[STATE_SNOW17_DEFICIT] + delta_HD_snow + delta_HD_T; // Deficit = heat deficit (mm) + + if (cNode->states[STATE_SNOW17_DEFICIT] <= 0.0) { // limits of heat deficit + cNode->states[STATE_SNOW17_DEFICIT] = 0.0; + } else if (cNode->states[STATE_SNOW17_DEFICIT] > (0.33*cNode->states[STATE_SNOW17_WI])) { + cNode->states[STATE_SNOW17_DEFICIT] = 0.33 * cNode->states[STATE_SNOW17_WI]; + } + + float SWE = 0.0; + // In SNOW-17 the snow cover is ripe when both (Deficit=0) & (W_q = W_qx) + if (cNode->states[STATE_SNOW17_WI] > 0) { + if ((Qw + cNode->states[STATE_SNOW17_WQ]) > ((cNode->states[STATE_SNOW17_DEFICIT]*(1+cNode->params[PARAM_SNOW17_PLWHC])) + W_qx) ) { // THEN the snow is RIPE + E = Qw + cNode->states[STATE_SNOW17_WQ] - W_qx - (cNode->states[STATE_SNOW17_DEFICIT]*(1+cNode->params[PARAM_SNOW17_PLWHC])); // Excess liquid water (mm) + cNode->states[STATE_SNOW17_WQ] = W_qx; // fills liquid water capacity + cNode->states[STATE_SNOW17_WI] = cNode->states[STATE_SNOW17_WI] + cNode->states[STATE_SNOW17_DEFICIT]; // W_i increases because water refreezes as heat deficit is decreased + cNode->states[STATE_SNOW17_DEFICIT] = 0; + } else if ((Qw >= cNode->states[STATE_SNOW17_DEFICIT])) {// %& ((Qw + cNode->W_q) <= ((cNode->Deficit*(1+cNode->params[PARAM_SNOW17_PLWHC])) + W_qx))) { // THEN the snow is NOT yet ripe, but ice is being melted + E = 0; + cNode->states[STATE_SNOW17_WQ] = cNode->states[STATE_SNOW17_WQ] + Qw - cNode->states[STATE_SNOW17_DEFICIT]; + cNode->states[STATE_SNOW17_WI] = cNode->states[STATE_SNOW17_WI] + cNode->states[STATE_SNOW17_DEFICIT]; // W_i increases because water refreezes as heat deficit is decreased + cNode->states[STATE_SNOW17_DEFICIT] = 0; + } else if ((Qw < cNode->states[STATE_SNOW17_DEFICIT])) { //elseif ((Qw + W_q) < cNode->Deficit)) { // THEN the snow is NOT yet ripe + E = 0; + cNode->states[STATE_SNOW17_WI] += Qw; // W_i increases because water refreezes as heat deficit is decreased + cNode->states[STATE_SNOW17_DEFICIT] -= Qw; + } + + SWE = cNode->states[STATE_SNOW17_WI] + cNode->states[STATE_SNOW17_WQ]; // + E; + } else { + // then no snow exists! + E = Qw; + SWE = 0; + cNode->states[STATE_SNOW17_WQ] = 0; + } + + if (cNode->states[STATE_SNOW17_DEFICIT] == 0) { + cNode->states[STATE_SNOW17_ATI] = 0; + } + + + // End of model execution + + /*if (SWE == 0.0) { + printf("pIn %f, pOut %f\n", cNode->pIn, cNode->pOut); + }*/ + + *swe = SWE; // total SWE (mm) at this time step + *melt = E / stepHours; +} + +void Snow17Model::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + size_t numNodes = nodes->size(); + size_t unused = 0; + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + Snow17GridNode *cNode = &(snowNodes[i]); + if (!node->gauge) { + unused++; + continue; + } + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_SNOW17_QTY); + + // Some of the parameters are special, deal with that here + /*if (!paramGrids->at(PARAM_CREST_IM)) { + cNode->params[PARAM_CREST_IM] /= 100.0; + }*/ + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_SNOW17_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && g_DEM->IsSpatialMatch(grid)) { + if (grid->data[node->y][node->x] == 0) { + grid->data[node->y][node->x] = 0.01; + } + cNode->params[paramI] *= grid->data[node->y][node->x]; + } else if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] == 0) { + grid->data[pt.y][pt.x] = 0.01; + //printf("Using nodata value in param %s\n", modelParamStrings[MODEL_CREST][paramI]); + } + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + + /*if (!paramGrids->at(PARAM_CREST_IWU)) { + cNode->soilMoisture = cNode->params[PARAM_CREST_IWU] * cNode->params[PARAM_CREST_WM] / 100.0; + } + + if (cNode->soilMoisture < 0.0) { + printf("Node Soil Moisture(%f) is less than 0, setting to 0.\n", cNode->soilMoisture); + cNode->soilMoisture = 0.0; + } else if (cNode->soilMoisture > cNode->params[PARAM_CREST_WM]) { + printf("Node Soil Moisture(%f) is greater than WM, setting to %f.\n", cNode->soilMoisture, cNode->params[PARAM_CREST_WM]); + } + + if (cNode->params[PARAM_CREST_IM] < 0.0) { + printf("Node Impervious Area(%f) is less than 0, setting to 0.\n", cNode->params[PARAM_CREST_IM]); + cNode->params[PARAM_CREST_IM] = 0.0; + } else if (cNode->params[PARAM_CREST_IM] > 1.0) { + printf("Node Impervious Area(%f) is greater than 1, setting to 1.\n", cNode->params[PARAM_CREST_IM]); + cNode->params[PARAM_CREST_IM] = 1.0; + } + + if (cNode->params[PARAM_CREST_B] < 0.0) { + printf("Node B (%f) is less than 0, setting to 0.\n", cNode->params[PARAM_CREST_B]); + cNode->params[PARAM_CREST_B] = 0.0; + } else if (cNode->params[PARAM_CREST_B] != cNode->params[PARAM_CREST_B]) { + printf("Node B (%f) NaN, setting to %f.\n", cNode->params[PARAM_CREST_B], 0.0); + cNode->params[PARAM_CREST_B] = 0.0; + }*/ + } + +} diff --git a/src/Snow17Model.h b/src/Snow17Model.h new file mode 100755 index 0000000..6c8b02a --- /dev/null +++ b/src/Snow17Model.h @@ -0,0 +1,42 @@ +#ifndef SNOW17_MODEL_H +#define SNOW17_MODEL_H + +#include "ModelBase.h" + +enum STATES_SNOW17 { + STATE_SNOW17_ATI, + STATE_SNOW17_WQ, + STATE_SNOW17_WI, + STATE_SNOW17_DEFICIT, + STATE_SNOW17_QTY +}; + +struct Snow17GridNode : BasicGridNode { + float params[PARAM_SNOW17_QTY]; + float states[STATE_SNOW17_QTY]; + + float P_atm; + +}; + +class Snow17Model : public SnowModel { + +public: + Snow17Model(); + ~Snow17Model(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void InitializeStates(TimeVar *beginTime, char *statePath); + void SaveStates(TimeVar *currentTime, char *statePath, GridWriterFull *gridWriter); + bool SnowBalance(float jday, float stepHours, std::vector<float> *precip, std::vector<float> *temp, std::vector<float> *melt, std::vector<float> *swe); + const char *GetName() { return "snow17"; } + +private: + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void SnowBalanceInt(GridNode *node, Snow17GridNode *cNode, float stepHours, float jday, float precipIn, float tempIn, float *melt, float *swe); + + std::vector<GridNode> *nodes; + std::vector<Snow17GridNode> snowNodes; + +}; + +#endif diff --git a/src/SnowCaliParamConfigSection.cpp b/src/SnowCaliParamConfigSection.cpp new file mode 100755 index 0000000..41f59ab --- /dev/null +++ b/src/SnowCaliParamConfigSection.cpp @@ -0,0 +1,113 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "SnowCaliParamConfigSection.h" + +std::map<std::string, SnowCaliParamConfigSection *> g_snowCaliParamConfigs[SNOW_QTY]; + +SnowCaliParamConfigSection::SnowCaliParamConfigSection(char *nameVal, SNOWS snowVal) { + strcpy(name, nameVal); + gauge = NULL; + snow = snowVal; + int numParams = numSnowParams[snow]; + modelParamMins = new float[numParams]; + modelParamMaxs = new float[numParams]; + modelParamInits = new float[numParams]; + paramsSet = new bool[numParams]; + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamMins, 0, sizeof(float)*numParams); + memset(modelParamInits, 0, sizeof(float)*numParams); + memset(paramsSet, 0, sizeof(bool)*numParams); + +} + +SnowCaliParamConfigSection::~SnowCaliParamConfigSection() { + delete [] modelParamMins; + delete [] modelParamMaxs; + delete [] modelParamInits; +} + +char *SnowCaliParamConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET SnowCaliParamConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numSnowParams[snow]; + + if (!strcasecmp(name, "gauge")) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + gauge = itr->second; + } else { + + if (!gauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + + //Lets see if this belongs to a parameter + for (int i = 0; i < numParams; i++) { + if (strcasecmp(name, snowParamStrings[snow][i]) == 0) { + + if (paramsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + float minVal = 0, maxVal = 0, initVal = 0; + int count = sscanf(value, "%f,%f,%f", &minVal, &maxVal, &initVal); + + if (count < 2) { + ERROR_LOGF("Parameter \"%s\" has invalid calibration values!", name); + return INVALID_RESULT; + } + + modelParamMins[i] = minVal; + modelParamMaxs[i] = maxVal; + modelParamInits[i] = initVal; + paramsSet[i] = true; + + return VALID_RESULT; + } + } + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET SnowCaliParamConfigSection::ValidateSection() { + int numParams = numSnowParams[snow]; + + if (!gauge) { + ERROR_LOG("The gauge on which calibration is to be performed was not set!"); + return INVALID_RESULT; + } + + for (int i = 0; i < numParams; i++) { + if (!paramsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", snowParamStrings[snow][i]); + return INVALID_RESULT; + } + } + + return VALID_RESULT; +} + +bool SnowCaliParamConfigSection::IsDuplicate(char *name, SNOWS snowVal) { + std::map<std::string, SnowCaliParamConfigSection *>::iterator itr = g_snowCaliParamConfigs[snowVal].find(name); + if (itr == g_snowCaliParamConfigs[snowVal].end()) { + return false; + } else { + return true; + } +} diff --git a/src/SnowCaliParamConfigSection.h b/src/SnowCaliParamConfigSection.h new file mode 100755 index 0000000..81045c8 --- /dev/null +++ b/src/SnowCaliParamConfigSection.h @@ -0,0 +1,40 @@ +#ifndef CONFIG_SNOWCALIPARAM_SECTION_H +#define CONFIG_SNOWCALIPARAM_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" +#include "ObjectiveFunc.h" + +class SnowCaliParamConfigSection : public ConfigSection { + + public: + SnowCaliParamConfigSection(char *nameVal, SNOWS routeVal); + ~SnowCaliParamConfigSection(); + + GaugeConfigSection *GetGauge() { return gauge; } + float *GetParamMins() { return modelParamMins; } + float *GetParamMaxs() { return modelParamMaxs; } + float *GetParamInits() { return modelParamInits; } + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name, SNOWS snowVal); + + private: + char name[CONFIG_MAX_LEN]; + SNOWS snow; + GaugeConfigSection *gauge; + float *modelParamMins; + float *modelParamMaxs; + float *modelParamInits; + bool *paramsSet; +}; + +extern std::map<std::string, SnowCaliParamConfigSection *> g_snowCaliParamConfigs[]; + +#endif diff --git a/src/SnowParamSetConfigSection.cpp b/src/SnowParamSetConfigSection.cpp new file mode 100755 index 0000000..c423efc --- /dev/null +++ b/src/SnowParamSetConfigSection.cpp @@ -0,0 +1,135 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "SnowParamSetConfigSection.h" + +std::map<std::string, SnowParamSetConfigSection *> g_snowParamSetConfigs[SNOW_QTY]; + +SnowParamSetConfigSection::SnowParamSetConfigSection(char *nameVal, SNOWS snowVal) { + strcpy(name, nameVal); + currentGauge = NULL; + currentParams = NULL; + currentParamsSet = NULL; + snow = snowVal; + paramGrids.resize(numSnowParams[snow]); +} + +SnowParamSetConfigSection::~SnowParamSetConfigSection() { + +} + +char *SnowParamSetConfigSection::GetName() { + return name; +} + +CONFIG_SEC_RET SnowParamSetConfigSection::ProcessKeyValue(char *name, char *value) { + int numParams = numSnowParams[snow]; + + if (strcasecmp(name, "gauge") == 0) { + + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", snowParamStrings[snow][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + if (IsDuplicateGauge(itr->second)) { + ERROR_LOGF("Duplicate gauge \"%s\" in parameter set!", value); + return INVALID_RESULT; + } + + currentGauge = itr->second; + currentParams = new float[numParams]; + currentParamsSet = new bool[numParams]; + memset(currentParams, 0, sizeof(float)*numParams); + memset(currentParamsSet, 0, sizeof(bool)*numParams); + } else { + // Lets see if this belongs to a parameter grid + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, snowParamGridStrings[snow][i]) == 0) { + paramGrids[i] = std::string(value); + return VALID_RESULT; + } + } + + + if (!currentGauge) { + ERROR_LOGF("Got parameter %s without a gauge being set!", name); + return INVALID_RESULT; + } + //Lets see if this belongs to a parameter scalar + for (int i = 0; i < numParams; i++) { + //printf("%i %i %s %s\n", model, i, modelParamStrings[model][i], name); + if (strcasecmp(name, snowParamStrings[snow][i]) == 0) { + + if (currentParamsSet[i]) { + ERROR_LOGF("Duplicate parameter \"%s\" in parameter set!", name); + return INVALID_RESULT; + } + + currentParams[i] = atof(value); + currentParamsSet[i] = true; + + return VALID_RESULT; + } + } + + //We got here so we must not know what this parameter is! + ERROR_LOGF("Unknown parameter name \"%s\".", name); + return INVALID_RESULT; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET SnowParamSetConfigSection::ValidateSection() { + int numParams = numSnowParams[snow]; + + if (currentGauge != NULL) { + //Lets verify the settings for the old gauge and then replace it + for (int i = 0; i < numParams; i++) { + if (!currentParamsSet[i]) { + ERROR_LOGF("Incomplete parameter set! Parameter \"%s\" was not given a value.", snowParamStrings[snow][i]); + return INVALID_RESULT; + } + } + delete [] currentParamsSet; + paramSettings.insert(std::pair<GaugeConfigSection *, float *>(currentGauge, currentParams)); + } + + + + return VALID_RESULT; +} + +bool SnowParamSetConfigSection::IsDuplicate(char *name, SNOWS snowVal) { + std::map<std::string, SnowParamSetConfigSection *>::iterator itr = g_snowParamSetConfigs[snowVal].find(name); + if (itr == g_snowParamSetConfigs[snowVal].end()) { + return false; + } else { + return true; + } +} + +bool SnowParamSetConfigSection::IsDuplicateGauge(GaugeConfigSection *gaugeVal) { + std::map<GaugeConfigSection *, float *>::iterator itr = paramSettings.find(gaugeVal); + if (itr == paramSettings.end()) { + return false; + } else { + return true; + } +} diff --git a/src/SnowParamSetConfigSection.h b/src/SnowParamSetConfigSection.h new file mode 100755 index 0000000..cafd4e2 --- /dev/null +++ b/src/SnowParamSetConfigSection.h @@ -0,0 +1,40 @@ +#ifndef CONFIG_SNOWPARAMSET_SECTION_H +#define CONFIG_SNOWPARAMSET_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "GaugeConfigSection.h" +#include "Model.h" + +class SnowParamSetConfigSection : public ConfigSection { + + public: + SnowParamSetConfigSection(char *nameVal, SNOWS snowVal); + ~SnowParamSetConfigSection(); + + char *GetName(); + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + std::map<GaugeConfigSection *, float *> *GetParamSettings() { return ¶mSettings; } + std::vector<std::string> *GetParamGrids() { return ¶mGrids; } + + static bool IsDuplicate(char *name, SNOWS snowVal); + + private: + bool IsDuplicateGauge(GaugeConfigSection *); + + char name[CONFIG_MAX_LEN]; + SNOWS snow; + GaugeConfigSection *currentGauge; + float *currentParams; + bool *currentParamsSet; + std::map<GaugeConfigSection *, float *> paramSettings; + std::vector<std::string> paramGrids; + + +}; + +extern std::map<std::string, SnowParamSetConfigSection *> g_snowParamSetConfigs[]; + +#endif diff --git a/src/TRMMDClip.cpp b/src/TRMMDClip.cpp new file mode 100644 index 0000000..d7c491d --- /dev/null +++ b/src/TRMMDClip.cpp @@ -0,0 +1,94 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "TRMMDGrid.h" +#include "AscGrid.h" + +int main(int argc, char *argv[]) { + + if (argc != 3 && argc != 7) { + printf("Use this program as TRMMDClip <input_filename> <output_filename> <top> <bottom> <left> <right>\n"); + return 0; + } + + char *filename = argv[1]; + char *outputfile = argv[2]; + float top = 50.0, bottom = -50.0, left = -180.0, right = 180.0; + + if (argc == 7) { + top = atof(argv[3]); + bottom = atof(argv[4]); + left = atof(argv[5]); + right = atof(argv[6]); + } + + int part = top / 0.25; + top = 0.25 * (float)(part); + + part = bottom / 0.25; + bottom = 0.25 * (float)(part); + + part = left / 0.25; + left = 0.25 * (float)(part); + + part = right / 0.25; + right = 0.25 * (float)(part); + + if (top > 50.0 || top < -50.0 || top <= bottom) { + printf("Top must be between 60 & -60 and > Bottom\n"); + return 0; + } + + if (bottom > 50 || bottom < -50) { + printf("Bottom must be between 60 & -60\n"); + return 0; + } + + if (left < -180.0 || left > 180.0 || left >= right) { + printf("Left must be between -180 & 180 and must be < Right\n"); + return 0; + } + + if (right < -180.0 || right > 180.0) { + printf("Right must be between -180 & 180\n"); + return 0; + } + + FloatGrid *outGrid = new FloatGrid; + outGrid->cellSize = 0.25; + outGrid->numCols = (right - left) / outGrid->cellSize; + outGrid->numRows = (top - bottom) / outGrid->cellSize; + outGrid->extent.bottom = bottom; + outGrid->extent.left = left; + outGrid->noData = -999.0; + outGrid->data = new float*[outGrid->numRows]; + for (long i = 0; i < outGrid->numRows; i++) { + outGrid->data[i] = new float[outGrid->numCols]; + } + //Fill in the rest of the BoundingBox + outGrid->extent.top = outGrid->extent.bottom + outGrid->numRows*outGrid->cellSize; + outGrid->extent.right = outGrid->extent.left + outGrid->numCols*outGrid->cellSize; + + FloatGrid *precipGrid = ReadFloatTRMMDGrid(filename); + + if (!precipGrid) { + printf("Failed to open file %s\n", filename); + return 0; + } + + int realTop = (precipGrid->extent.top - outGrid->extent.top) / outGrid->cellSize; + int realLeft = (outGrid->extent.left - precipGrid->extent.left) / outGrid->cellSize; + + + printf("Real top is %i, left is %i\n", realTop, realLeft); + + for (long y = realTop; y < realTop + outGrid->numRows; y++) { + for (long x = realLeft; x < realLeft + outGrid->numCols; x++) { + outGrid->data[y - realTop][x - realLeft] = precipGrid->data[y][x]; + } + } + + WriteFloatAscGrid(outputfile, outGrid); + + return 1; +} diff --git a/src/TRMMDGrid.cpp b/src/TRMMDGrid.cpp new file mode 100755 index 0000000..ccb83fb --- /dev/null +++ b/src/TRMMDGrid.cpp @@ -0,0 +1,81 @@ +#include <cstdio> +#include <zlib.h> +#include "Messages.h" +#include "TRMMDGrid.h" + +FloatGrid *ReadFloatTRMMDGrid(char *file, FloatGrid *grid) { + + gzFile fileH; + + fileH = gzopen(file, "rb"); + if (fileH == NULL) { + return NULL; + } + + + //gzread(fileH, unprocessed, 2880); + + if (!grid) { + grid = new FloatGrid(); + grid->numCols = 1440; + grid->numRows = 400; + grid->cellSize = 0.25; + grid->extent.bottom = -50.0; + grid->extent.left = -180.0; + grid->data = new float*[grid->numRows](); + if (!grid->data) { + WARNING_LOGF("TRMM Daily file %s too large (out of memory) with %li rows", file, grid->numRows); + delete grid; + gzclose(fileH); + return NULL; + } + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new float[grid->numCols](); + if (!grid->data[i]) { + WARNING_LOGF("TRMM Daily file %s too large (out of memory) with %li cols", file, grid->numCols); + delete grid; + gzclose(fileH); + return NULL; + } + } + } + float *shortData = new float[grid->numCols]; + if (shortData) { + WARNING_LOGF("TRMM Daily file %s too large (out of memory) temporary storage", file); + delete grid; + gzclose(fileH); + return NULL; + } + + for (long i = 0; i < grid->numRows; i++) { + if (gzread(fileH, shortData, sizeof(float) * grid->numCols) != sizeof(short) * grid->numCols) { + WARNING_LOGF("TRMM Daily file %s corrupt?", file); + delete grid; + delete [] shortData; + gzclose(fileH); + return NULL; + } + for (int j = 0; j < grid->numCols; j++) { + int realJ = (j > 720) ? (j - 720) : (j + 720); // Flip this about the Y-axis + unsigned int blah = *(unsigned int*)&(shortData[j]); + unsigned int bleh = __builtin_bswap32(blah); + grid->data[grid->numRows - 1 - i][realJ] = *(float*)&bleh; + } + } + delete [] shortData; + + //Fill in the rest of the BoundingBox + grid->extent.top = grid->extent.bottom + grid->numRows*grid->cellSize; + grid->extent.right = grid->extent.left + grid->numCols*grid->cellSize; + + gzclose(fileH); + + return grid; + +} + +FloatGrid *ReadFloatTRMMDGrid(char *file) { + + return ReadFloatTRMMDGrid(file, NULL); + +} diff --git a/src/TRMMDGrid.h b/src/TRMMDGrid.h new file mode 100755 index 0000000..8d34703 --- /dev/null +++ b/src/TRMMDGrid.h @@ -0,0 +1,9 @@ +#ifndef TRMMD_GRID_H +#define TRMMD_GRID_H + +#include "Grid.h" + +FloatGrid *ReadFloatTRMMDGrid(char *file, FloatGrid *grid); +FloatGrid *ReadFloatTRMMDGrid(char *file); + +#endif diff --git a/src/TRMMRTClip.cpp b/src/TRMMRTClip.cpp new file mode 100644 index 0000000..836a87a --- /dev/null +++ b/src/TRMMRTClip.cpp @@ -0,0 +1,94 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "TRMMRTGrid.h" +#include "AscGrid.h" + +int main(int argc, char *argv[]) { + + if (argc != 3 && argc != 7) { + printf("Use this program as TRMMRTClip <input_filename> <output_filename> <top> <bottom> <left> <right>\n"); + return 0; + } + + char *filename = argv[1]; + char *outputfile = argv[2]; + float top = 60.0, bottom = -60.0, left = -180.0, right = 180.0; + + if (argc == 7) { + top = atof(argv[3]); + bottom = atof(argv[4]); + left = atof(argv[5]); + right = atof(argv[6]); + } + + int part = top / 0.25; + top = 0.25 * (float)(part); + + part = bottom / 0.25; + bottom = 0.25 * (float)(part); + + part = left / 0.25; + left = 0.25 * (float)(part); + + part = right / 0.25; + right = 0.25 * (float)(part); + + if (top > 60.0 || top < -60.0 || top <= bottom) { + printf("Top must be between 60 & -60 and > Bottom\n"); + return 0; + } + + if (bottom > 60 || bottom < -60) { + printf("Bottom must be between 60 & -60\n"); + return 0; + } + + if (left < -180.0 || left > 180.0 || left >= right) { + printf("Left must be between -180 & 180 and must be < Right\n"); + return 0; + } + + if (right < -180.0 || right > 180.0) { + printf("Right must be between -180 & 180\n"); + return 0; + } + + FloatGrid *outGrid = new FloatGrid; + outGrid->cellSize = 0.25; + outGrid->numCols = (right - left) / outGrid->cellSize; + outGrid->numRows = (top - bottom) / outGrid->cellSize; + outGrid->extent.bottom = bottom; + outGrid->extent.left = left; + outGrid->noData = -999.0; + outGrid->data = new float*[outGrid->numRows]; + for (long i = 0; i < outGrid->numRows; i++) { + outGrid->data[i] = new float[outGrid->numCols]; + } + //Fill in the rest of the BoundingBox + outGrid->extent.top = outGrid->extent.bottom + outGrid->numRows*outGrid->cellSize; + outGrid->extent.right = outGrid->extent.left + outGrid->numCols*outGrid->cellSize; + + FloatGrid *precipGrid = ReadFloatTRMMRTGrid(filename); + + if (!precipGrid) { + printf("Failed to open file %s\n", filename); + return 0; + } + + int realTop = (precipGrid->extent.top - outGrid->extent.top) / outGrid->cellSize; + int realLeft = (outGrid->extent.left - precipGrid->extent.left) / outGrid->cellSize; + + + printf("Real top is %i, left is %i\n", realTop, realLeft); + + for (long y = realTop; y < realTop + outGrid->numRows; y++) { + for (long x = realLeft; x < realLeft + outGrid->numCols; x++) { + outGrid->data[y - realTop][x - realLeft] = precipGrid->data[y][x]; + } + } + + WriteFloatAscGrid(outputfile, outGrid); + + return 1; +} diff --git a/src/TRMMRTGrid.cpp b/src/TRMMRTGrid.cpp new file mode 100755 index 0000000..3ecfff9 --- /dev/null +++ b/src/TRMMRTGrid.cpp @@ -0,0 +1,87 @@ +#include <cstdio> +#include <zlib.h> +#include "Messages.h" +#include "TRMMRTGrid.h" + +FloatGrid *ReadFloatTRMMRTGrid(char *file, FloatGrid *grid) { + + gzFile fileH; + + fileH = gzopen(file, "rb"); + if (fileH == NULL) { + return NULL; + } + + char unprocessed[2880]; + + gzread(fileH, unprocessed, 2880); + + if (!grid) { + grid = new FloatGrid(); + grid->numCols = 1440; + grid->numRows = 480; + grid->cellSize = 0.25; + grid->extent.bottom = -60.0; + grid->extent.left = -180.0; + grid->data = new float*[grid->numRows](); + if (!grid->data) { + WARNING_LOGF("TRMMRT file %s too large (out of memory) with %li rows", file, grid->numRows); + delete grid; + gzclose(fileH); + return NULL; + } + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new float[grid->numCols](); + if (!grid->data[i]) { + WARNING_LOGF("TRMMRT file %s too large (out of memory) with %li colums", file, grid->numCols); + delete grid; + gzclose(fileH); + return NULL; + } + } + } + unsigned short *shortData = new unsigned short[grid->numCols]; + if (!shortData) { + WARNING_LOGF("TRMMRT file %s too large (out of memory)", file); + delete grid; + gzclose(fileH); + return NULL; + } + + + for (long i = 0; i < grid->numRows; i++) { + if (gzread(fileH, shortData, sizeof(short) * grid->numCols) != (int)sizeof(short) * grid->numCols) { + WARNING_LOGF("TRMMRT file %s corrupt?", file); + delete grid; + delete [] shortData; + gzclose(fileH); + return NULL; + } + for (int j = 0; j < grid->numCols; j++) { + int realJ = (j >= 720) ? (j - 720) : (j + 720); // Flip this about the Y-axis + unsigned short realData = (shortData[j] >> 8) | ((shortData[j] & 0xFF) << 8); + float floatData = 0; + if (realData >= 0 && realData <= 30000) { + floatData = ((float)realData) / 100.0; + } + grid->data[i][realJ] = floatData; + } + } + + delete [] shortData; + + //Fill in the rest of the BoundingBox + grid->extent.top = grid->extent.bottom + grid->numRows*grid->cellSize; + grid->extent.right = grid->extent.left + grid->numCols*grid->cellSize; + + gzclose(fileH); + + return grid; + +} + +FloatGrid *ReadFloatTRMMRTGrid(char *file) { + + return ReadFloatTRMMRTGrid(file, NULL); + +} diff --git a/src/TRMMRTGrid.h b/src/TRMMRTGrid.h new file mode 100755 index 0000000..9574e27 --- /dev/null +++ b/src/TRMMRTGrid.h @@ -0,0 +1,9 @@ +#ifndef TRMMRT_GRID_H +#define TRMMRT_GRID_H + +#include "Grid.h" + +FloatGrid *ReadFloatTRMMRTGrid(char *file, FloatGrid *grid); +FloatGrid *ReadFloatTRMMRTGrid(char *file); + +#endif diff --git a/src/TRMMV6Clip.cpp b/src/TRMMV6Clip.cpp new file mode 100644 index 0000000..da238f8 --- /dev/null +++ b/src/TRMMV6Clip.cpp @@ -0,0 +1,94 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "TRMMV6Grid.h" +#include "AscGrid.h" + +int main(int argc, char *argv[]) { + + if (argc != 3 && argc != 7) { + printf("Use this program as TRMMV6Clip <input_filename> <output_filename> <top> <bottom> <left> <right>\n"); + return 0; + } + + char *filename = argv[1]; + char *outputfile = argv[2]; + float top = 50.0, bottom = -50.0, left = -180.0, right = 180.0; + + if (argc == 7) { + top = atof(argv[3]); + bottom = atof(argv[4]); + left = atof(argv[5]); + right = atof(argv[6]); + } + + int part = top / 0.25; + top = 0.25 * (float)(part); + + part = bottom / 0.25; + bottom = 0.25 * (float)(part); + + part = left / 0.25; + left = 0.25 * (float)(part); + + part = right / 0.25; + right = 0.25 * (float)(part); + + if (top > 50.0 || top < -50.0 || top <= bottom) { + printf("Top must be between 50 & -50 and > Bottom\n"); + return 0; + } + + if (bottom > 50.0 || bottom < -50.0) { + printf("Bottom must be between 50 & -50\n"); + return 0; + } + + if (left < -180.0 || left > 180.0 || left >= right) { + printf("Left must be between -180 & 180 and must be < Right\n"); + return 0; + } + + if (right < -180.0 || right > 180.0) { + printf("Right must be between -180 & 180\n"); + return 0; + } + + FloatGrid *outGrid = new FloatGrid; + outGrid->cellSize = 0.25; + outGrid->numCols = (right - left) / outGrid->cellSize; + outGrid->numRows = (top - bottom) / outGrid->cellSize; + outGrid->extent.bottom = bottom; + outGrid->extent.left = left; + outGrid->noData = -9999.0; + outGrid->data = new float*[outGrid->numRows]; + for (long i = 0; i < outGrid->numRows; i++) { + outGrid->data[i] = new float[outGrid->numCols]; + } + //Fill in the rest of the BoundingBox + outGrid->extent.top = outGrid->extent.bottom + outGrid->numRows*outGrid->cellSize; + outGrid->extent.right = outGrid->extent.left + outGrid->numCols*outGrid->cellSize; + + FloatGrid *precipGrid = ReadFloatTRMMV6Grid(filename); + + if (!precipGrid) { + printf("Failed to open file %s\n", filename); + return 0; + } + + int realTop = (precipGrid->extent.top - outGrid->extent.top) / outGrid->cellSize; + int realLeft = (outGrid->extent.left - precipGrid->extent.left) / outGrid->cellSize; + + + printf("Real top is %i, left is %i (%f %f)\n", realTop, realLeft, precipGrid->extent.top, outGrid->extent.top); + + for (long y = realTop; y < realTop + outGrid->numRows; y++) { + for (long x = realLeft; x < realLeft + outGrid->numCols; x++) { + outGrid->data[y - realTop][x - realLeft] = precipGrid->data[y][x]; + } + } + + WriteFloatAscGrid(outputfile, outGrid); + + return 1; +} diff --git a/src/TRMMV6Grid.cpp b/src/TRMMV6Grid.cpp new file mode 100644 index 0000000..4fcd2c7 --- /dev/null +++ b/src/TRMMV6Grid.cpp @@ -0,0 +1,115 @@ +#include <stdio.h> +#include <hdf/mfhdf.h> +#include "TRMMV6Grid.h" + +union FloatInt { + unsigned int data; + float floatVal; +}; + +void change_endian(unsigned int &x); + +void change_endian(unsigned int &val) { + val = (val<<24) | ((val<<8) & 0x00ff0000) | + ((val>>8) & 0x0000ff00) | (val>>24); +} + +FloatGrid *ReadFloatTRMMV6Grid(char *file, FloatGrid *grid) { + + /*FILE *fileH; + + fileH = fopen(file, "rb"); + if (fileH == NULL) { + return NULL; + }*/ + //printf("Size is %i\n", sizeof(FloatInt)); + + //char unprocessed[298]; + + //fread(unprocessed, 298, 1, fileH); + + if (!grid) { + grid = new FloatGrid(); + grid->numCols = 1440; + grid->numRows = 400; + grid->cellSize = 0.25; + grid->extent.bottom = -50.0; + grid->extent.left = -180.0; + grid->data = new float*[grid->numRows]; + grid->noData = -9999.0; + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new float[grid->numCols]; + } + } + + int sd_id, sds_id, sds_index; + //int status; + int start[3]; + + sd_id = SDstart(file, DFACC_READ); + if (sd_id == -1) { + printf("Failed to open HDF file!\n"); + } + sds_index = SDnametoindex(sd_id, "precipitation"); + if (sds_index == -1) { + printf("Failed to find precipitation field!\n"); + } else { + //printf("Index is %i\n", sds_index); + } + sds_id = SDselect(sd_id, sds_index); + if (sds_id == -1) { + printf("Failed to select index!\n"); + } else { + //printf("SDS id is %i\n", sds_index); + } + start[0] = 0; start[1] = 0; start[2] = 0; + char sd_name[256]; + + int number_type,dimsizes[3],rank,n_attributes; + + SDgetinfo(sds_id, sd_name, &rank,dimsizes, &number_type, &n_attributes); + //printf("Dim sizes are %i %i %i %s\n", dimsizes[0], dimsizes[1], dimsizes[2], sd_name); + + float testData[1][1440][400]; + + SDreaddata(sds_id, start, NULL, dimsizes, testData); + //printf("Status is %i\n", status); + SDendaccess(sds_id); + SDend(sd_id); + + for (long x = 0; x < 1440; x++) { + for (long y = 0; y < 400; y++) { + grid->data[399 - y][x] = testData[0][x][y]; + } + } + //printf("Got here!\n"); + + /*FloatInt *shortData = new FloatInt[grid->numCols]; + + for (long i = 0; i < grid->numRows; i++) { + fread(shortData, sizeof(FloatInt), grid->numCols, fileH); + for (int j = 0; j < grid->numCols; j++) { + change_endian(shortData[j].data); + grid->data[i][j] = shortData[j].floatVal; + } + } + + delete [] shortData;*/ + + //Fill in the rest of the BoundingBox + grid->extent.top = grid->extent.bottom + grid->numRows*grid->cellSize; + grid->extent.right = grid->extent.left + grid->numCols*grid->cellSize; + + //fclose(fileH); + + return grid; + +} + +FloatGrid *ReadFloatTRMMV6Grid(char *file) { + + FloatGrid *grid = NULL; + + return ReadFloatTRMMV6Grid(file, grid); + +} diff --git a/src/TRMMV6Grid.h b/src/TRMMV6Grid.h new file mode 100644 index 0000000..68b4ace --- /dev/null +++ b/src/TRMMV6Grid.h @@ -0,0 +1,9 @@ +#ifndef TRMMV6_GRID_H +#define TRMMV6_GRID_H + +#include "Grid.h" + +FloatGrid *ReadFloatTRMMV6Grid(char *file, FloatGrid *grid); +FloatGrid *ReadFloatTRMMV6Grid(char *file); + +#endif diff --git a/src/TaskConfigSection.cpp b/src/TaskConfigSection.cpp new file mode 100755 index 0000000..92a3674 --- /dev/null +++ b/src/TaskConfigSection.cpp @@ -0,0 +1,700 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "GriddedOutput.h" +#include "TaskConfigSection.h" + +std::map<std::string, TaskConfigSection *> g_taskConfigs; + +TaskConfigSection::TaskConfigSection(const char *nameVal) { + strcpy(name, nameVal); + styleSet = false; + modelSet = false; + routeSet = false; + snowSet = false; + inundationSet = false; + basinSet = false; + precipSet = false; + qpfSet = false; + petSet = false; + tempSet = false; + tempFSet = false; + outputSet = false; + paramsSet = false; + routingParamsSet = false; + snowParamsSet = false; + inundationParamsSet = false; + + timestepSet = false; + timestepLRSet = false; + timeStateSet = false; + timeBeginSet = false; + timeBeginLRSet = false; + timeWarmEndSet = false; + timeEndSet = false; + caliParamSet = false; + snowCaliParamSet = false; + inundationCaliParamSet = false; + routingCaliParamSet = false; + defaultParamsSet = false; + defaultGauge = NULL; + qpf = NULL; + tempf = NULL; + stdGrid[0] = 0; + avgGrid[0] = 0; + scGrid[0] = 0; + actionGrid[0] = 0; + minorGrid[0] = 0; + moderateGrid[0] = 0; + majorGrid[0] = 0; + actionSDGrid[0] = 0; + minorSDGrid[0] = 0; + moderateSDGrid[0] = 0; + majorSDGrid[0] = 0; + memset(daFile, 0, CONFIG_MAX_LEN); + memset(preloadFile, 0, CONFIG_MAX_LEN); + memset(coFile, 0, CONFIG_MAX_LEN); + griddedOutputs = OG_NONE; + routing = ROUTE_QTY; + snow = SNOW_QTY; + inundation = INUNDATION_QTY; + temp = NULL; +} + +TaskConfigSection::~TaskConfigSection() { + +} + +char *TaskConfigSection::GetName() { + return name; +} + +char *TaskConfigSection::GetOutput() { + return output; +} + +char *TaskConfigSection::GetState() { + return state; +} + +char *TaskConfigSection::GetStdGrid() { + return stdGrid; +} + +char *TaskConfigSection::GetAvgGrid() { + return avgGrid; +} + +char *TaskConfigSection::GetScGrid() { + return scGrid; +} + +char *TaskConfigSection::GetActionGrid() { + return actionGrid; +} + +char *TaskConfigSection::GetMinorGrid() { + return minorGrid; +} + +char *TaskConfigSection::GetModerateGrid() { + return moderateGrid; +} + +char *TaskConfigSection::GetMajorGrid() { + return majorGrid; +} + +char *TaskConfigSection::GetActionSDGrid() { + return actionSDGrid; +} + +char *TaskConfigSection::GetMinorSDGrid() { + return minorSDGrid; +} + +char *TaskConfigSection::GetModerateSDGrid() { + return moderateSDGrid; +} + +char *TaskConfigSection::GetMajorSDGrid() { + return majorSDGrid; +} + +char *TaskConfigSection::GetPreloadForcings() { + return preloadFile; +} + +char *TaskConfigSection::GetDAFile() { + return daFile; +} + +char *TaskConfigSection::GetCOFile() { + return coFile; +} + +TimeVar *TaskConfigSection::GetTimeBegin() { + return &timeBegin; +} + +TimeVar *TaskConfigSection::GetTimeState() { + return &timeState; +} + +TimeVar *TaskConfigSection::GetTimeWarmEnd() { + return &timeWarmEnd; +} + +TimeVar *TaskConfigSection::GetTimeEnd() { + return &timeEnd; +} + +TimeVar *TaskConfigSection::GetTimeBeginLR() { + if (!timestepLRSet || !timeBeginLRSet) { + return NULL; + } + return &timeBeginLR; +} + +TimeUnit *TaskConfigSection::GetTimeStep() { + return &timeStep; +} + +TimeUnit *TaskConfigSection::GetTimeStepLR() { + if (!timestepLRSet || !timeBeginLRSet) { + return NULL; + } + return &timeStepLR; +} + +PrecipConfigSection *TaskConfigSection::GetPrecipSec() { + return precip; +} + +PrecipConfigSection *TaskConfigSection::GetQPFSec() { + return qpf; +} + +PETConfigSection *TaskConfigSection::GetPETSec() { + return pet; +} + +TempConfigSection *TaskConfigSection::GetTempSec() { + return temp; +} + +TempConfigSection *TaskConfigSection::GetTempFSec() { + return tempf; +} + +BasinConfigSection *TaskConfigSection::GetBasinSec() { + return basin; +} + +ParamSetConfigSection *TaskConfigSection::GetParamsSec() { + return params; +} + +CaliParamConfigSection *TaskConfigSection::GetCaliParamSec() { + return caliParam; +} + +RoutingParamSetConfigSection *TaskConfigSection::GetRoutingParamsSec() { + return paramsRouting; +} + +RoutingCaliParamConfigSection *TaskConfigSection::GetRoutingCaliParamSec() { + return caliParamRouting; +} + +SnowParamSetConfigSection *TaskConfigSection::GetSnowParamsSec() { + return paramsSnow; +} + +SnowCaliParamConfigSection *TaskConfigSection::GetSnowCaliParamSec() { + return caliParamSnow; +} + +InundationParamSetConfigSection *TaskConfigSection::GetInundationParamsSec() { + return paramsInundation; +} + +InundationCaliParamConfigSection *TaskConfigSection::GetInundationCaliParamSec() { + return caliParamInundation; +} + +RUNSTYLE TaskConfigSection::GetRunStyle() { + return style; +} + +MODELS TaskConfigSection::GetModel() { + return model; +} + +ROUTES TaskConfigSection::GetRouting() { + return routing; +} + +SNOWS TaskConfigSection::GetSnow() { + return snow; +} + +INUNDATIONS TaskConfigSection::GetInundation() { + return inundation; +} + +GaugeConfigSection *TaskConfigSection::GetDefaultGauge() { + return defaultGauge; +} + +CONFIG_SEC_RET TaskConfigSection::ProcessKeyValue(char *name, char *value) { + + if (!strcasecmp(name, "style")) { + for (int i = 0; i < STYLE_QTY; i++) { + if (!strcasecmp(value, runStyleStrings[i])) { + styleSet = true; + style = (RUNSTYLE)i; + return VALID_RESULT; + } + } + ERROR_LOGF("Unknown run style option \"%s\"!", value); + INFO_LOGF("Valid run style options are \"%s\"", "SIMU, SIMU_RP, CALI_ARS, CALI_DREAM, CLIP_BASIN, CLIP_GAUGE, BASIN_AVG"); + return INVALID_RESULT; + } else if (!strcasecmp(name, "model")) { + for (int i = 0; i < MODEL_QTY; i++) { + if (!strcasecmp(value, modelStrings[i])) { + modelSet = true; + model = (MODELS)i; + return VALID_RESULT; + } + } + ERROR_LOGF("Unknown water balance model option \"%s\"!", value); + INFO_LOGF("Valid water balance options are \"%s\"", "CREST, SAC, HP"); + return INVALID_RESULT; + } else if (!strcasecmp(name, "routing")) { + for (int i = 0; i < ROUTE_QTY; i++) { + if (!strcasecmp(value, routeStrings[i])) { + routeSet = true; + routing = (ROUTES)i; + return VALID_RESULT; + } + } + ERROR_LOGF("Unknown routing option \"%s\"!", value); + INFO_LOGF("Valid routing options are \"%s\"", "LR, KW"); + return INVALID_RESULT; + } else if (!strcasecmp(name, "snow")) { + for (int i = 0; i < SNOW_QTY; i++) { + if (!strcasecmp(value, snowStrings[i])) { + snowSet = true; + snow = (SNOWS)i; + return VALID_RESULT; + } + } + ERROR_LOGF("Unknown snow option \"%s\"!", value); + INFO_LOGF("Valid snow options are \"%s\"", "SNOW17"); + return INVALID_RESULT; + } else if (!strcasecmp(name, "inundation")) { + for (int i = 0; i < INUNDATION_QTY; i++) { + if (!strcasecmp(value, inundationStrings[i])) { + inundationSet = true; + inundation = (INUNDATIONS)i; + return VALID_RESULT; + } + } + ERROR_LOGF("Unknown inundation option \"%s\"!", value); + INFO_LOGF("Valid inundation options are \"%s\"", "SIMPLEINUNDATION, VCINUNDATION"); + return INVALID_RESULT; + } else if (!strcasecmp(name, "basin")) { + TOLOWER(value); + std::map<std::string, BasinConfigSection *>::iterator itr = g_basinConfigs.find(value); + if (itr == g_basinConfigs.end()) { + ERROR_LOGF("Unknown basin \"%s\"!", value); + return INVALID_RESULT; + } + basin = itr->second; + basinSet = true; + } else if (!strcasecmp(name, "defaultparamsgauge")) { + TOLOWER(value); + std::map<std::string, GaugeConfigSection *>::iterator itr = g_gaugeConfigs.find(value); + if (itr == g_gaugeConfigs.end()) { + ERROR_LOGF("Unknown default parameter gauge \"%s\"!", value); + return INVALID_RESULT; + } + defaultGauge = itr->second; + defaultParamsSet = true; + } else if (!strcasecmp(name, "precip")) { + TOLOWER(value); + std::map<std::string, PrecipConfigSection *>::iterator itr = g_precipConfigs.find(value); + if (itr == g_precipConfigs.end()) { + ERROR_LOGF("Unknown precip setting \"%s\"!", value); + return INVALID_RESULT; + } + precip = itr->second; + precipSet = true; + } else if (!strcasecmp(name, "precipforecast")) { + TOLOWER(value); + std::map<std::string, PrecipConfigSection *>::iterator itr = g_precipConfigs.find(value); + if (itr == g_precipConfigs.end()) { + ERROR_LOGF("Unknown precip forecast setting \"%s\"!", value); + return INVALID_RESULT; + } + qpf = itr->second; + qpfSet = true; + } else if (!strcasecmp(name, "pet")) { + TOLOWER(value); + std::map<std::string, PETConfigSection *>::iterator itr = g_petConfigs.find(value); + if (itr == g_petConfigs.end()) { + ERROR_LOGF("Unknown PET setting \"%s\"!", value); + return INVALID_RESULT; + } + pet = itr->second; + petSet = true; + } else if (!strcasecmp(name, "temp")) { + TOLOWER(value); + std::map<std::string, TempConfigSection *>::iterator itr = g_tempConfigs.find(value); + if (itr == g_tempConfigs.end()) { + ERROR_LOGF("Unknown temp setting \"%s\"!", value); + return INVALID_RESULT; + } + temp = itr->second; + tempSet = true; + } else if (!strcasecmp(name, "tempforecast")) { + TOLOWER(value); + std::map<std::string, TempConfigSection *>::iterator itr = g_tempConfigs.find(value); + if (itr == g_tempConfigs.end()) { + ERROR_LOGF("Unknown temp forecast setting \"%s\"!", value); + return INVALID_RESULT; + } + tempf = itr->second; + tempFSet = true; + } else if (!strcasecmp(name, "param_set")) { + if (!modelSet) { + ERROR_LOG("The MODEL setting must be specified before the PARAM_SET setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, ParamSetConfigSection *>::iterator itr = g_paramSetConfigs[model].find(value); + if (itr == g_paramSetConfigs[model].end()) { + ERROR_LOGF("Unknown parameter set \"%s\"!", value); + return INVALID_RESULT; + } + params = itr->second; + paramsSet = true; + } else if (!strcasecmp(name, "routing_param_set")) { + if (!routeSet) { + ERROR_LOG("The ROUTING setting must be specified before the ROUTING_PARAM_SET setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, RoutingParamSetConfigSection *>::iterator itr = g_routingParamSetConfigs[routing].find(value); + if (itr == g_routingParamSetConfigs[routing].end()) { + ERROR_LOGF("Unknown routing parameter set \"%s\"!", value); + return INVALID_RESULT; + } + paramsRouting = itr->second; + routingParamsSet = true; + } else if (!strcasecmp(name, "snow_param_set")) { + if (!snowSet) { + ERROR_LOG("The SNOW setting must be specified before the SNOW_PARAM_SET setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, SnowParamSetConfigSection *>::iterator itr = g_snowParamSetConfigs[snow].find(value); + if (itr == g_snowParamSetConfigs[snow].end()) { + ERROR_LOGF("Unknown snow parameter set \"%s\"!", value); + return INVALID_RESULT; + } + paramsSnow = itr->second; + snowParamsSet = true; + } else if (!strcasecmp(name, "inundation_param_set")) { + if (!inundationSet) { + ERROR_LOG("The INUNDATION setting must be specified before the INUNDATION_PARAM_SET setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, InundationParamSetConfigSection *>::iterator itr = g_inundationParamSetConfigs[inundation].find(value); + if (itr == g_inundationParamSetConfigs[inundation].end()) { + ERROR_LOGF("Unknown inundation parameter set \"%s\"!", value); + return INVALID_RESULT; + } + paramsInundation = itr->second; + inundationParamsSet = true; + } else if (!strcasecmp(name, "output")) { + strcpy(output, value); + outputSet = true; + } else if (!strcasecmp(name, "preload_file")) { + strcpy(preloadFile, value); + } else if (!strcasecmp(name, "da_file")) { + strcpy(daFile, value); + } else if (!strcasecmp(name, "co_file")) { + strcpy(coFile, value); + } else if (!strcasecmp(name, "states")) { + strcpy(state, value); + stateSet = true; + } else if (!strcasecmp(name, "output_grids")) { + if (!LoadGriddedOutputs(value)) { + return INVALID_RESULT; + } + } else if (!strcasecmp(name, "rp_stdgrid")) { + strcpy(stdGrid, value); + } else if (!strcasecmp(name, "rp_avggrid")) { + strcpy(avgGrid, value); + } else if (!strcasecmp(name, "rp_csgrid")) { + strcpy(scGrid, value); + } else if (!strcasecmp(name, "action_grid")) { + strcpy(actionGrid, value); + } else if (!strcasecmp(name, "minor_grid")) { + strcpy(minorGrid, value); + } else if (!strcasecmp(name, "moderate_grid")) { + strcpy(moderateGrid, value); + } else if (!strcasecmp(name, "major_grid")) { + strcpy(majorGrid, value); + } else if (!strcasecmp(name, "action_sd_grid")) { + strcpy(actionSDGrid, value); + } else if (!strcasecmp(name, "minor_sd_grid")) { + strcpy(minorSDGrid, value); + } else if (!strcasecmp(name, "moderate_sd_grid")) { + strcpy(moderateSDGrid, value); + } else if (!strcasecmp(name, "major_sd_grid")) { + strcpy(majorSDGrid, value); + } else if (!strcasecmp(name, "timestep")) { + SUPPORTED_TIME_UNITS result = timeStep.ParseUnit(value); + if (result == TIME_UNIT_QTY) { + ERROR_LOGF("Unknown timestep option \"%s\"", value); + return INVALID_RESULT; + } + timestepSet = true; + } else if (!strcasecmp(name, "timestep_lr")) { + SUPPORTED_TIME_UNITS result = timeStepLR.ParseUnit(value); + if (result == TIME_UNIT_QTY) { + ERROR_LOGF("Unknown timestep long range option \"%s\"", value); + return INVALID_RESULT; + } + timestepLRSet = true; + } else if (!strcasecmp(name, "time_state")) { + if (!timeState.LoadTime(value)) { + ERROR_LOGF("Unknown time state option \"%s\"", value); + return INVALID_RESULT; + + } + timeStateSet = true; + } else if (!strcasecmp(name, "time_begin")) { + if (!timeBegin.LoadTime(value)) { + ERROR_LOGF("Unknown time begin option \"%s\"", value); + return INVALID_RESULT; + + } + timeBeginSet = true; + } else if (!strcasecmp(name, "time_begin_lr")) { + if (!timeBeginLR.LoadTime(value)) { + ERROR_LOGF("Unknown time begin long range option \"%s\"", value); + return INVALID_RESULT; + + } + timeBeginLRSet = true; + }else if (!strcasecmp(name, "time_warmend")) { + if (!timeWarmEnd.LoadTime(value)) { + ERROR_LOGF("Unknown time warm end option \"%s\"", value); + return INVALID_RESULT; + + } + timeWarmEndSet = true; + } else if (!strcasecmp(name, "time_end")) { + if (!timeEnd.LoadTime(value)) { + ERROR_LOGF("Unknown time end option \"%s\"", value); + return INVALID_RESULT; + } + timeEndSet = true; + } else if (!strcasecmp(name, "cali_param")) { + if (!modelSet) { + ERROR_LOG("The MODEL setting must be specified before the CALI_PARAM setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, CaliParamConfigSection *>::iterator itr = g_caliParamConfigs[model].find(value); + if (itr == g_caliParamConfigs[model].end()) { + ERROR_LOGF("Unknown calibration parameter set \"%s\"!", value); + return INVALID_RESULT; + } + caliParam = itr->second; + caliParamSet = true; + } else if (!strcasecmp(name, "routing_cali_param")) { + if (!routeSet) { + ERROR_LOG("The ROUTING setting must be specified before the ROUTING_CALI_PARAM setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, RoutingCaliParamConfigSection *>::iterator itr = g_routingCaliParamConfigs[routing].find(value); + if (itr == g_routingCaliParamConfigs[routing].end()) { + ERROR_LOGF("Unknown routing calibration parameter set \"%s\"!", value); + return INVALID_RESULT; + } + caliParamRouting = itr->second; + routingCaliParamSet = true; + } else if (!strcasecmp(name, "snow_cali_param")) { + if (!snowSet) { + ERROR_LOG("The SNOW setting must be specified before the SNOW_CALI_PARAM setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, SnowCaliParamConfigSection *>::iterator itr = g_snowCaliParamConfigs[snow].find(value); + if (itr == g_snowCaliParamConfigs[snow].end()) { + ERROR_LOGF("Unknown snow calibration parameter set \"%s\"!", value); + return INVALID_RESULT; + } + caliParamSnow = itr->second; + snowCaliParamSet = true; + } else if (!strcasecmp(name, "inundation_cali_param")) { + if (!inundationSet) { + ERROR_LOG("The INUNDATION setting must be specified before the INUNDATION_CALI_PARAM setting in the task!"); + return INVALID_RESULT; + } + TOLOWER(value); + std::map<std::string, InundationCaliParamConfigSection *>::iterator itr = g_inundationCaliParamConfigs[inundation].find(value); + if (itr == g_inundationCaliParamConfigs[inundation].end()) { + ERROR_LOGF("Unknown inundation calibration parameter set \"%s\"!", value); + return INVALID_RESULT; + } + caliParamInundation = itr->second; + inundationCaliParamSet = true; + } else { + ERROR_LOGF("Unknown task configuration option \"%s\"", name); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +bool TaskConfigSection::LoadGriddedOutputs(char *value) { + + char *part = strtok(value, "|"); + while (part != NULL) { + bool matchFound = false; + for (int i = 0; i < OG_QTY; i++) { + if (!strcasecmp(part, GriddedOutputText[i])) { + griddedOutputs |= GriddedOutputFlags[i]; + matchFound = true; + break; + } + } + if (!matchFound) { + ERROR_LOGF("Unknown output grids flag \"%s\"", part); + return false; + } + part = strtok(NULL, "|"); + } + + return true; +} + +CONFIG_SEC_RET TaskConfigSection::ValidateSection() { + if (!styleSet) { + ERROR_LOG("The run style was not specified"); + return INVALID_RESULT; + } else if (!modelSet) { + ERROR_LOG("The water balance model was not specified"); + return INVALID_RESULT; + } else if (!basinSet) { + ERROR_LOG("The basin was not specified"); + return INVALID_RESULT; + } else if (!precipSet) { + ERROR_LOG("The precip was not specified"); + return INVALID_RESULT; + } else if (!petSet) { + ERROR_LOG("The pet was not specified"); + return INVALID_RESULT; + } else if (!outputSet) { + ERROR_LOG("The output directory was not specified"); + return INVALID_RESULT; + } else if (!paramsSet) { + ERROR_LOG("The water balance parameter set was not specified"); + return INVALID_RESULT; + } else if (routeSet && !routingParamsSet) { + ERROR_LOG("The routing parameter set was not specified"); + return INVALID_RESULT; + } else if (!timestepSet) { + ERROR_LOG("The timestep was not specified"); + return INVALID_RESULT; + } else if (!timeBeginSet) { + ERROR_LOG("The beginning time was not specified"); + return INVALID_RESULT; + } else if (!timeEndSet) { + ERROR_LOG("The ending time was not specified"); + return INVALID_RESULT; + } else if (snowSet && !snowParamsSet) { + ERROR_LOG("The snow parameter set was not specified"); + return INVALID_RESULT; + } else if (snowSet && !tempSet) { + ERROR_LOG("The temperature forcing was not specified"); + return INVALID_RESULT; + } else if (inundationSet && !inundationParamsSet) { + ERROR_LOG("The inundation parameter set was not specified"); + return INVALID_RESULT; + } + + if (IsCalibrationRunStyle(style)) { + if (!caliParamSet) { + ERROR_LOG("The calibration water balance parameter set was not specified"); + return INVALID_RESULT; + } + + if (!routingCaliParamSet) { + ERROR_LOG("The calibration routing parameter set was not specified"); + return INVALID_RESULT; + } + + if (snowSet && !snowCaliParamSet) { + ERROR_LOG("The calibration snow parameter set was not specified"); + return INVALID_RESULT; + } + + char *gaugeWB = caliParam->GetGauge()->GetName(); + char *gaugeR = caliParamRouting->GetGauge()->GetName(); + char *gaugeS = NULL; + if (snowSet) { + gaugeS = caliParamSnow->GetGauge()->GetName(); + } + bool foundWB = false, foundR = false, foundS = false; + std::vector<GaugeConfigSection *> *bGauges = basin->GetGauges(); + for (size_t i = 0; i < bGauges->size(); i++) { + if (!strcasecmp(gaugeWB, bGauges->at(i)->GetName())) { + foundWB = true; + } + if (!strcasecmp(gaugeR, bGauges->at(i)->GetName())) { + foundR = true; + } + if (snowSet && !strcasecmp(gaugeS, bGauges->at(i)->GetName())) { + foundS = true; + } + } + + if (!foundWB) { + ERROR_LOG("The calibration gauge (water balance cali param) was not found in the basin!"); + return INVALID_RESULT; + } + if (!foundR) { + ERROR_LOG("The calibration gauge (routing cali param) was not found in the basin!"); + return INVALID_RESULT; + } + if (snowSet && !foundS) { + ERROR_LOG("The calibration gauge (snow cali param) was not found in the basin!"); + return INVALID_RESULT; + } + } + + if (!timeWarmEndSet) { + timeWarmEnd = timeBegin; + } + + return VALID_RESULT; +} + +bool TaskConfigSection::IsDuplicate(char *name) { + std::map<std::string, TaskConfigSection *>::iterator itr = g_taskConfigs.find(name); + if (itr == g_taskConfigs.end()) { + return false; + } else { + return true; + } +} diff --git a/src/TaskConfigSection.h b/src/TaskConfigSection.h new file mode 100755 index 0000000..c47a12a --- /dev/null +++ b/src/TaskConfigSection.h @@ -0,0 +1,128 @@ +#ifndef CONFIG_TASK_SECTION_H +#define CONFIG_TASK_SECTION_H + +#include <map> +#include "Defines.h" +#include "ConfigSection.h" +#include "BasinConfigSection.h" +#include "Model.h" +#include "ParamSetConfigSection.h" +#include "PETConfigSection.h" +#include "PrecipConfigSection.h" +#include "TempConfigSection.h" +#include "CaliParamConfigSection.h" +#include "RoutingParamSetConfigSection.h" +#include "RoutingCaliParamConfigSection.h" +#include "SnowParamSetConfigSection.h" +#include "SnowCaliParamConfigSection.h" +#include "InundationParamSetConfigSection.h" +#include "InundationCaliParamConfigSection.h" +#include "GaugeConfigSection.h" +#include "TimeUnit.h" +#include "TimeVar.h" + +class TaskConfigSection : public ConfigSection { + +public: + TaskConfigSection(const char *nameVal); + ~TaskConfigSection(); + + char *GetName(); + char *GetOutput(); + char *GetState(); + char *GetStdGrid(); + char *GetAvgGrid(); + char *GetScGrid(); + char *GetActionGrid(); + char *GetMinorGrid(); + char *GetModerateGrid(); + char *GetMajorGrid(); + char *GetActionSDGrid(); + char *GetMinorSDGrid(); + char *GetModerateSDGrid(); + char *GetMajorSDGrid(); + char *GetPreloadForcings(); + char *GetDAFile(); + char *GetCOFile(); + TimeVar *GetTimeBegin(); + TimeVar *GetTimeWarmEnd(); + TimeVar *GetTimeEnd(); + TimeVar *GetTimeState(); + TimeUnit *GetTimeStep(); + TimeUnit *GetTimeStepLR(); + TimeVar *GetTimeBeginLR(); + PrecipConfigSection *GetPrecipSec(); + PrecipConfigSection *GetQPFSec(); + PETConfigSection *GetPETSec(); + TempConfigSection *GetTempSec(); + TempConfigSection *GetTempFSec(); + BasinConfigSection *GetBasinSec(); + ParamSetConfigSection *GetParamsSec(); + CaliParamConfigSection *GetCaliParamSec(); + RoutingParamSetConfigSection *GetRoutingParamsSec(); + RoutingCaliParamConfigSection *GetRoutingCaliParamSec(); + SnowParamSetConfigSection *GetSnowParamsSec(); + SnowCaliParamConfigSection *GetSnowCaliParamSec(); + InundationParamSetConfigSection *GetInundationParamsSec(); + InundationCaliParamConfigSection *GetInundationCaliParamSec(); + RUNSTYLE GetRunStyle(); + MODELS GetModel(); + ROUTES GetRouting(); + SNOWS GetSnow(); + INUNDATIONS GetInundation(); + GaugeConfigSection *GetDefaultGauge(); + bool UseStates() { return stateSet; } + bool SaveStates() { return (stateSet && timeStateSet); } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + int GetGriddedOutputs() { return griddedOutputs; } + + static bool IsDuplicate(char *name); + +private: + bool styleSet, modelSet, basinSet, precipSet, qpfSet, petSet, outputSet, stateSet, paramsSet, timestepSet, timeStateSet, timeBeginSet, timeWarmEndSet, timeEndSet, caliParamSet, routingParamsSet, routingCaliParamSet, defaultParamsSet, routeSet; + bool snowParamsSet, snowCaliParamSet, snowSet, tempSet, tempFSet; + bool inundationParamsSet, inundationCaliParamSet, inundationSet; + bool timeBeginLRSet, timestepLRSet; + char output[CONFIG_MAX_LEN], state[CONFIG_MAX_LEN]; + char name[CONFIG_MAX_LEN]; + char stdGrid[CONFIG_MAX_LEN], avgGrid[CONFIG_MAX_LEN], scGrid[CONFIG_MAX_LEN]; + char actionGrid[CONFIG_MAX_LEN], minorGrid[CONFIG_MAX_LEN], moderateGrid[CONFIG_MAX_LEN], majorGrid[CONFIG_MAX_LEN]; + char actionSDGrid[CONFIG_MAX_LEN], minorSDGrid[CONFIG_MAX_LEN], moderateSDGrid[CONFIG_MAX_LEN], majorSDGrid[CONFIG_MAX_LEN]; + char preloadFile[CONFIG_MAX_LEN]; + char daFile[CONFIG_MAX_LEN]; + char coFile[CONFIG_MAX_LEN]; + MODELS model; + ROUTES routing; + SNOWS snow; + INUNDATIONS inundation; + BasinConfigSection *basin; + PrecipConfigSection *precip, *qpf; + PETConfigSection *pet; + TempConfigSection *temp, *tempf; + ParamSetConfigSection *params; + CaliParamConfigSection *caliParam; + RoutingParamSetConfigSection *paramsRouting; + RoutingCaliParamConfigSection *caliParamRouting; + SnowParamSetConfigSection *paramsSnow; + SnowCaliParamConfigSection *caliParamSnow; + InundationParamSetConfigSection *paramsInundation; + InundationCaliParamConfigSection *caliParamInundation; + GaugeConfigSection *defaultGauge; + TimeUnit timeStep; + TimeUnit timeStepLR; + RUNSTYLE style; + TimeVar timeBegin; + TimeVar timeWarmEnd; + TimeVar timeEnd; + TimeVar timeState; + TimeVar timeBeginLR; + int griddedOutputs; + + bool LoadGriddedOutputs(char *value); + +}; + +extern std::map<std::string, TaskConfigSection *> g_taskConfigs; + +#endif diff --git a/src/TempConfigSection.cpp b/src/TempConfigSection.cpp new file mode 100755 index 0000000..42f2955 --- /dev/null +++ b/src/TempConfigSection.cpp @@ -0,0 +1,99 @@ +#include <cstdio> +#include <cstring> +#include <string> +#include "Messages.h" +#include "TempConfigSection.h" + +std::map<std::string, TempConfigSection *> g_tempConfigs; + +TempConfigSection::TempConfigSection() { + locSet = false; + freqSet = false; + nameSet = false; + typeSet = false; + unitSet = false; + demSet = false; +} + +TempConfigSection::~TempConfigSection() { + +} + +DatedName *TempConfigSection::GetFileName() { + return &fileName; +} + +CONFIG_SEC_RET TempConfigSection::ProcessKeyValue(char *name, char *value) { + + if (!strcasecmp(name, "type")) { + SUPPORTED_TEMP_TYPES result = type.ParseType(value); + if (result == TEMP_TYPE_QTY) { + ERROR_LOGF("Unknown type option \"%s\"", value); + return INVALID_RESULT; + } + typeSet = true; + } else if (!strcasecmp(name, "unit")) { + bool result = false; + if (!strcasecmp(value, "c")) { + result = true; + } + if (!result) { + ERROR_LOGF("Unknown unit option \"%s\"", value); + return INVALID_RESULT; + } + unitSet = true; + } else if (!strcasecmp(name, "freq")) { + SUPPORTED_TIME_UNITS result = freq.ParseUnit(value); + if (result == TIME_UNIT_QTY) { + ERROR_LOGF("Unknown frequency option \"%s\"", value); + return INVALID_RESULT; + } + freqSet = true; + } else if (!strcasecmp(name, "loc")) { + strcpy(loc, value); + locSet = true; + } else if (!strcasecmp(name, "dem")) { + strcpy(dem, value); + demSet = true; + } else if (!strcasecmp(name, "name")) { + fileName.SetNameStr(value); + nameSet = true; + } + return VALID_RESULT; +} + +CONFIG_SEC_RET TempConfigSection::ValidateSection() { + if (!typeSet) { + ERROR_LOG("The type was not specified"); + return INVALID_RESULT; + } else if (!unitSet) { + ERROR_LOG("The unit was not specified"); + return INVALID_RESULT; + } else if (!freqSet) { + ERROR_LOG("The frequency was not specified"); + return INVALID_RESULT; + } else if (!locSet) { + ERROR_LOG("The location was not specified"); + return INVALID_RESULT; + } else if (!nameSet) { + ERROR_LOG("The file name was not specified"); + return INVALID_RESULT; + } + + if (!fileName.ProcessNameLoose(&freq)) { + ERROR_LOG("The file name was specified with improper resolution"); + return INVALID_RESULT; + } + + return VALID_RESULT; +} + +bool TempConfigSection::IsDuplicate(char *name) { + std::map<std::string, TempConfigSection *>::iterator itr = g_tempConfigs.find(std::string(name)); + if (itr == g_tempConfigs.end()) { + return false; + } else { + return true; + } +} + diff --git a/src/TempConfigSection.h b/src/TempConfigSection.h new file mode 100755 index 0000000..9a03573 --- /dev/null +++ b/src/TempConfigSection.h @@ -0,0 +1,43 @@ +#ifndef CONFIG_TEMP_SECTION_H +#define CONFIG_TEMP_SECTION_H + +#include <map> +#include "Defines.h" +#include "TimeUnit.h" +#include "DistancePerTimeUnits.h" +#include "DatedName.h" +#include "TempType.h" +#include "ConfigSection.h" + +class TempConfigSection : public ConfigSection { + + public: + TempConfigSection(); + ~TempConfigSection(); + + DatedName *GetFileName(); + TimeUnit *GetFreq() { return &freq; } + char *GetLoc() { return loc; } + char *GetDEM() { return dem; } + TimeUnit *GetUnitTime() { return unit.GetTime(); } + SUPPORTED_TEMP_TYPES GetType() { return type.GetType(); } + CONFIG_SEC_RET ProcessKeyValue(char *name, char *value); + CONFIG_SEC_RET ValidateSection(); + + static bool IsDuplicate(char *name); + + private: + bool locSet, freqSet, nameSet, unitSet, typeSet, demSet; + char loc[CONFIG_MAX_LEN]; + char dem[CONFIG_MAX_LEN]; + DatedName fileName; + TimeUnit freq; + DistancePerTimeUnits unit; + TempType type; + + +}; + +extern std::map<std::string, TempConfigSection *> g_tempConfigs; + +#endif diff --git a/src/TempReader.cpp b/src/TempReader.cpp new file mode 100755 index 0000000..32c610f --- /dev/null +++ b/src/TempReader.cpp @@ -0,0 +1,101 @@ +#include <cmath> +#include <cstdio> +#include <cstring> +#include "Messages.h" +#include "AscGrid.h" +#include "BifGrid.h" +#include "TifGrid.h" +#include "TempReader.h" + +void TempReader::ReadDEM(char *file) { + tempDEM = ReadFloatTifGrid(file); + if (!tempDEM) { + WARNING_LOGF("Failed to load temperature grid DEM %s\n", file); + } else { + INFO_LOGF("Successfully loaded temperature grid DEM %s\n", file); + } +} + +bool TempReader::Read(char *file, SUPPORTED_TEMP_TYPES type, std::vector<GridNode> *nodes, std::vector<float> *currentTemp, std::vector<float> *prevTemp, bool hasF) { + if (!strcmp(lastTempFile, file)) { + if (prevTemp) { + for (size_t i = 0; i < nodes->size(); i++) { + currentTemp->at(i) = prevTemp->at(i); + } + } + return true; // This is the same temp file that we read last time, we assume currentPET is still valid! + } + + if (!hasF) { + // Update this here so we recheck for missing files & don't recheck for forecast precip + strcpy(lastTempFile, file); + } + + FloatGrid *tempGrid = NULL; + + switch (type) { + case TEMP_ASCII: + tempGrid = ReadFloatAscGrid(file); + break; + case TEMP_TIF: + tempGrid = ReadFloatTifGrid(file); + break; + default: + ERROR_LOG("Unsupported Temp format!"); + break; + } + + if (!tempGrid) { + // The temp file was not found! We return zeros if there is no qpf. + if (!hasF) { + for (size_t i = 0; i < nodes->size(); i++) { + currentTemp->at(i) = 0; + } + } + return false; + } + + if (hasF) { + // Update this here so we recheck for missing files & don't recheck for forecast precip + strcpy(lastTempFile, file); + } + + // We have two options now... Either the temp grid & the basic grids are the same + // Or they are different! + + if (g_DEM->IsSpatialMatch(tempGrid)) { + // The grids are the same! Our life is easy! + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (tempGrid->data[node->y][node->x] != tempGrid->noData) { + currentTemp->at(i) = tempGrid->data[node->y][node->x]; + } else { + currentTemp->at(i) = 0.0; + } + } + + } else { + // The grids are different, we must do some resampling fun. + GridLoc pt; + for (size_t i = 0; i < nodes->size(); i++) { + GridNode *node = &(nodes->at(i)); + if (tempGrid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt) && tempGrid->data[pt.y][pt.x] != tempGrid->noData) { + if (tempDEM && tempDEM->IsSpatialMatch(tempGrid)) { + float temp = tempGrid->data[pt.y][pt.x]; + float diffHeight = g_DEM->data[node->y][node->x] - tempDEM->data[pt.y][pt.x]; + float tempMod = -0.0065 * diffHeight; + currentTemp->at(i) = temp + tempMod; + } else { + currentTemp->at(i) = tempGrid->data[pt.y][pt.x]; + } + } else { + currentTemp->at(i) = 0.0; + } + } + } + + // We don't actually need to keep the PET grid in memory anymore + delete tempGrid; + + return true; +} diff --git a/src/TempReader.h b/src/TempReader.h new file mode 100755 index 0000000..ae97ca9 --- /dev/null +++ b/src/TempReader.h @@ -0,0 +1,21 @@ +#ifndef TEMP_READER_H +#define TEMP_READER_H + +#include <vector> +#include "Defines.h" +#include "BasicGrids.h" +#include "TempType.h" + +class TempReader { + public: + bool Read(char *file, SUPPORTED_TEMP_TYPES type, std::vector<GridNode> *nodes, std::vector<float> *currentTemp, std::vector<float> *prevTemp = NULL, bool hasF = false); + void ReadDEM(char *file); + void SetNullDEM() { tempDEM = NULL; } + + private: + char lastTempFile[CONFIG_MAX_LEN*2]; + FloatGrid *tempDEM; + +}; + +#endif diff --git a/src/TempType.cpp b/src/TempType.cpp new file mode 100755 index 0000000..e7fb57b --- /dev/null +++ b/src/TempType.cpp @@ -0,0 +1,29 @@ +#include <cstring> +#include "TempType.h" + +const char *tempTypeStrings[] = { + "asc", + "tif", +}; + +SUPPORTED_TEMP_TYPES TempType::GetType() { + return type; +} + +SUPPORTED_TEMP_TYPES TempType::ParseType(char *typeStr) { + SUPPORTED_TEMP_TYPES result = TEMP_TYPE_QTY; + + for (int i = 0; i < TEMP_TYPE_QTY; i++) { + if (!strcasecmp(tempTypeStrings[i], typeStr)) { + result = (SUPPORTED_TEMP_TYPES)i; + break; + } + } + + type = result; + + return result; + +} + + diff --git a/src/TempType.h b/src/TempType.h new file mode 100755 index 0000000..84ec6c1 --- /dev/null +++ b/src/TempType.h @@ -0,0 +1,22 @@ +#ifndef TEMP_TYPE_H +#define TEMP_TYPE_H + +enum SUPPORTED_TEMP_TYPES { + TEMP_ASCII, + TEMP_TIF, + TEMP_TYPE_QTY, +}; + +extern const char *tempTypeStrings[]; + +class TempType { + + public: + SUPPORTED_TEMP_TYPES GetType(); + SUPPORTED_TEMP_TYPES ParseType(char *typeStr); + + private: + SUPPORTED_TEMP_TYPES type; +}; + +#endif diff --git a/src/TifGrid.cpp b/src/TifGrid.cpp new file mode 100755 index 0000000..53b8e99 --- /dev/null +++ b/src/TifGrid.cpp @@ -0,0 +1,278 @@ +#include <limits> +#include <cstdio> +#include <stdlib.h> +#include "xtiffio.h" +#include "geotiffio.h" +#include "Messages.h" +#include "TifGrid.h" + +#define TIFFTAG_GDAL_METADATA 42112 +#define TIFFTAG_GDAL_NODATA 42113 + +static const TIFFFieldInfo xtiffFieldInfo[] = { + { TIFFTAG_GDAL_METADATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM, true, false, (char*) "GDALMetadata" }, + { TIFFTAG_GDAL_NODATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM, true, false, (char*) "GDALNoDataValue" } +}; + +static TIFFExtendProc TIFFParentExtender = NULL; +static void TIFFExtenderInit(); +static void TIFFDefaultDirectory(TIFF *tif); + + +static void TIFFExtenderInit() { + static int first_time=1; + + if (!first_time) { + return; /* Been there. Done that. */ + } + first_time = 0; + + /* Grab the inherited method and install */ + TIFFParentExtender = TIFFSetTagExtender(TIFFDefaultDirectory); + + TIFFSetErrorHandler(NULL); +} + +static void TIFFDefaultDirectory(TIFF *tif) { + /* Install the extended Tag field info */ + TIFFMergeFieldInfo(tif, xtiffFieldInfo, sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0])); + + /* Since an XTIFF client module may have overridden + * * the default directory method, we call it now to + * * allow it to set up the rest of its own methods. + * */ + + if (TIFFParentExtender) { + (*TIFFParentExtender)(tif); + } +} + +FloatGrid *ReadFloatTifGrid(const char *file) { + return ReadFloatTifGrid(file, NULL); +} + +FloatGrid *ReadFloatTifGrid(const char *file, FloatGrid *incGrid) { + + TIFFExtenderInit(); + + FloatGrid *grid = incGrid; + TIFF *tif = NULL; + GTIF *gtif = NULL; + + tif = XTIFFOpen(file, "r"); + if (!tif) { + return NULL; + } + + gtif = GTIFNew(tif); + if (!gtif) { + XTIFFClose(tif); + return NULL; + } + + unsigned short sampleFormat, samplesPerPixel, bitsPerSample; + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleFormat); + + if (sampleFormat != SAMPLEFORMAT_IEEEFP || bitsPerSample != 32 || samplesPerPixel != 1) { + WARNING_LOGF("%s is not a supported Float32 GeoTiff", file); + GTIFFree(gtif); + XTIFFClose(tif); + return NULL; + } + + int width, height; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + + short tiepointsize, pixscalesize; + double* tiepoints;//[6]; + double* pixscale;//[3]; + TIFFGetField(tif, TIFFTAG_GEOTIEPOINTS, &tiepointsize, + &tiepoints); + TIFFGetField(tif, TIFFTAG_GEOPIXELSCALE, &pixscalesize, + &pixscale); + + if (!grid || grid->numCols != width || grid->numRows != height) { + if (grid) { + delete grid; + } + grid = new FloatGrid(); + grid->numCols = width; + grid->numRows = height; + grid->data = new float*[grid->numRows](); + if (!grid->data) { + WARNING_LOGF("TIF file %s too large (out of memory) with %li rows", file, grid->numRows); + delete grid; + GTIFFree(gtif); + XTIFFClose(tif); + return NULL; + } + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new float[grid->numCols](); + if (!grid->data[i]) { + WARNING_LOGF("TIF file %s too large (out of memory) with %li columns", file, grid->numCols); + delete grid; + GTIFFree(gtif); + XTIFFClose(tif); + return NULL; + } + } + } + + char *noData = NULL; + if (TIFFGetField(tif, TIFFTAG_GDAL_NODATA, &noData)) { + grid->noData = atof(noData); + } else { + grid->noData = std::numeric_limits<float>::quiet_NaN(); + } + grid->cellSize = pixscale[0]; + grid->extent.top = tiepoints[4]; + grid->extent.left = tiepoints[3]; + grid->extent.bottom = tiepoints[4]-(pixscale[1] * float(height)); + grid->extent.right = tiepoints[3]+(pixscale[0] * float(width)); + + for (long i = 0; i < grid->numRows; i++) { + if (TIFFReadScanline(tif, grid->data[i], (unsigned int)i, 1) == -1) { + WARNING_LOGF("TIF file %s corrupt? (scanline read failed)", file); + delete grid; + GTIFFree(gtif); + XTIFFClose(tif); + return NULL; + } + } + + GTIFFree(gtif); + XTIFFClose(tif); + + return grid; + +} + +void WriteFloatTifGrid(const char *file, FloatGrid *grid) { + + TIFFExtenderInit(); + + TIFF *tif = NULL; + GTIF *gtif = NULL; + + tif = XTIFFOpen(file, "w"); + if (!tif) { + return; + } + + gtif = GTIFNew(tif); + if (!gtif) { + XTIFFClose(tif); + return; + } + + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, grid->numCols); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, grid->numRows); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 20); + char buf[100]; + sprintf(buf, "%f", grid->noData); + TIFFSetField(tif, TIFFTAG_GDAL_NODATA, buf); + + double tiepoints[6]; + double pixscale[3]; + + pixscale[0] = grid->cellSize; + pixscale[1] = grid->cellSize; + pixscale[2] = 0.0; + tiepoints[0] = 0; + tiepoints[1] = 0; + tiepoints[2] = 0; + tiepoints[5] = 0; + tiepoints[4] = grid->extent.top; + tiepoints[3] = grid->extent.left; + //grid->extent.bottom = tiepoints[4]-(pixscale[1] * float(height)); + //grid->extent.right = tiepoints[3]+(pixscale[0] * float(width));*/ + + TIFFSetField(tif, TIFFTAG_GEOTIEPOINTS, 6, tiepoints); + TIFFSetField(tif, TIFFTAG_GEOPIXELSCALE, 3, pixscale); + + for (long i = 0; i < grid->numRows; i++) { + if (TIFFWriteScanline(tif, grid->data[i], (unsigned int)i, 0) == -1) { + printf("eek!\n"); + } + } + + GTIFFree(gtif); + XTIFFClose(tif); + +} + +LongGrid *ReadLongTifGrid(const char *file) { + + LongGrid *grid = NULL; + TIFF *tif = NULL; + GTIF *gtif = NULL; + + TIFFSetErrorHandler(NULL); + + tif = XTIFFOpen(file, "r"); + if (!tif) { + return NULL; + } + + gtif = GTIFNew(tif); + if (!gtif) { + XTIFFClose(tif); + return NULL; + } + + unsigned short sampleFormat, samplesPerPixel, bitsPerSample; + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); + TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleFormat); + + if (sampleFormat != SAMPLEFORMAT_INT || bitsPerSample != 32 || samplesPerPixel != 1) { + WARNING_LOGF("%s is not a supported Int GeoTiff", file); + GTIFFree(gtif); + XTIFFClose(tif); + return NULL; + } + + int width, height; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + + short tiepointsize, pixscalesize; + double* tiepoints;//[6]; + double* pixscale;//[3]; + TIFFGetField(tif, TIFFTAG_GEOTIEPOINTS, &tiepointsize, + &tiepoints); + TIFFGetField(tif, TIFFTAG_GEOPIXELSCALE, &pixscalesize, + &pixscale); + + grid = new LongGrid(); + + grid->numCols = width; + grid->numRows = height; + grid->cellSize = pixscale[0]; + grid->extent.top = tiepoints[4]; + grid->extent.left = tiepoints[3]; + grid->extent.bottom = tiepoints[4]-(pixscale[1] * float(height)); + grid->extent.right = tiepoints[3]+(pixscale[0] * float(width)); + + grid->data = new long*[grid->numRows]; + for (long i = 0; i < grid->numRows; i++) { + grid->data[i] = new long[grid->numCols]; + if (TIFFReadScanline(tif, grid->data[i], (unsigned int)i, 1) == -1) { + printf("eek!\n"); + } + } + + GTIFFree(gtif); + XTIFFClose(tif); + + return grid; + +} diff --git a/src/TifGrid.h b/src/TifGrid.h new file mode 100755 index 0000000..39dffea --- /dev/null +++ b/src/TifGrid.h @@ -0,0 +1,11 @@ +#ifndef TIF_GRID_H +#define TIF_GRID_H + +#include "Grid.h" + +FloatGrid *ReadFloatTifGrid(const char *file); +FloatGrid *ReadFloatTifGrid(const char *file, FloatGrid *incGrid); +void WriteFloatTifGrid(const char *file, FloatGrid *grid); +LongGrid *ReadLongTifGrid(const char *file); + +#endif diff --git a/src/TimeSeries.cpp b/src/TimeSeries.cpp new file mode 100755 index 0000000..ed61cc3 --- /dev/null +++ b/src/TimeSeries.cpp @@ -0,0 +1,86 @@ +#include <limits> +#include <cstdio> +#include "Defines.h" +#include "Messages.h" +#include "TimeSeries.h" + +void TimeSeries::LoadTimeSeries(char *file) { + FILE *tsFile; + + tsFile = fopen(file, "rb"); + if (tsFile == NULL) { + WARNING_LOGF("Failed to open time series file %s", file); + return; + } + + //printf("struct size is %i\n", sizeof(TSDataPoint)); + + //Get number of file lines + /*int fileLines = 0, temp; + while ( (temp = fgetc(tsFile)) != EOF) { + fileLines += (temp == 10); + } + fseek(tsFile, 0, SEEK_SET); + + for (int i = 0; i < fileLines; i++) {*/ + while (!feof(tsFile)) { + char buffer[CONFIG_MAX_LEN]; + float dataValue; + if (fscanf(tsFile, "%[^,],%f%*c", &(buffer[0]), &dataValue) == 2) { + TSDataPoint *pt = new TSDataPoint; + pt->time.LoadTimeExcel(buffer); + pt->value = dataValue; + timeSeries.push_back(pt); + } else { + fgets(buffer, CONFIG_MAX_LEN, tsFile); + } + } + + fclose(tsFile); + lastIndex = 0; +} + +void TimeSeries::PutValueAtTime(char *timeBuffer, float dataValue) { + TSDataPoint *pt = new TSDataPoint; + pt->time.LoadTimeExcel(timeBuffer); + pt->value = dataValue; + timeSeries.push_back(pt); +} + +float TimeSeries::GetValueAtTime(TimeVar *wantTime) { + for (size_t i = lastIndex; i < timeSeries.size(); i++) { + if (timeSeries[i]->time == (*wantTime)) { + lastIndex = i; + return timeSeries[i]->value; + } + if ((*wantTime) < timeSeries[i]->time) { + return std::numeric_limits<float>::quiet_NaN(); + } + } + /*for (std::vector<TSDataPoint>::iterator itr = timeSeries.begin(); itr != timeSeries.end(); itr++) { + TSDataPoint *pt = &(*itr); + if (pt->time == (*wantTime)) { + return pt->value; + } + }*/ + + return std::numeric_limits<float>::quiet_NaN(); + +} + +float TimeSeries::GetValueNearTime(TimeVar *wantTime, time_t diff) { + for (size_t i = lastIndex; i < timeSeries.size(); i++) { + if (timeSeries[i]->time == (*wantTime)) { + lastIndex = i; + return timeSeries[i]->value; + } else if ((*wantTime) < timeSeries[i]->time) { + if ((timeSeries[i]->time.currentTimeSec - wantTime->currentTimeSec) < diff) { + return timeSeries[i]->value; + } + return std::numeric_limits<float>::quiet_NaN(); + } + } + + return std::numeric_limits<float>::quiet_NaN(); + +} diff --git a/src/TimeSeries.h b/src/TimeSeries.h new file mode 100755 index 0000000..a6d36a0 --- /dev/null +++ b/src/TimeSeries.h @@ -0,0 +1,28 @@ +#ifndef TIME_SERIES_H +#define TIME_SERIES_H + +#include <vector> +#include <cstdio> +#include "TimeVar.h" + +struct TSDataPoint { + TimeVar time; + float value; +}; + +class TimeSeries { + + public: + void LoadTimeSeries(char *file); + void PutValueAtTime(char *timeBuffer, float dataValue); + float GetValueAtTime(TimeVar *wantTime); + float GetValueNearTime(TimeVar *wantTime, time_t diff); + size_t GetNumberOfObs() { return timeSeries.size(); } + + private: + std::vector<TSDataPoint*> timeSeries; + size_t lastIndex; + +}; + +#endif diff --git a/src/TimeUnit.cpp b/src/TimeUnit.cpp new file mode 100755 index 0000000..73ef329 --- /dev/null +++ b/src/TimeUnit.cpp @@ -0,0 +1,79 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include "Defines.h" +#include "Messages.h" +#include "TimeUnit.h" + +const char *TimeUnitText[] = { + "y", + "m", + "d", + "h", + "u", + "s", +}; + +const unsigned long TimeUnitSeconds[] = { + 60*60*24*365, + 60*60*24*30, + 60*60*24, + 60*60, + 60, + 1, +}; + +unsigned long TimeUnit::GetTimeInSec() { + return timeInSec; +} + +int TimeUnit::GetTimeModifier() { + return timeModifier; +} + +SUPPORTED_TIME_UNITS TimeUnit::GetTimeUnit() { + return timeUnit; +} + +SUPPORTED_TIME_UNITS TimeUnit::ParseUnit(char *unitText) { + size_t len = strlen(unitText); + SUPPORTED_TIME_UNITS result = TIME_UNIT_QTY; + char modifier[CONFIG_MAX_LEN]; + char *unitStr = unitText; + int intModifier = 0; + unsigned long time = 0; + + for (size_t i = 0; i < len; i++) { + if ((*unitStr >= '0' && *unitStr <= '9')) { + modifier[i] = *unitStr; + unitStr++; + } else if (i == 0) { + modifier[0] = '1'; + modifier[1] = 0; + break; + } else { + modifier[i] = 0; + break; + } + } + + intModifier = atoi(modifier); + + for (int i = 0; i < TIME_UNIT_QTY; i++) { + if (!strcasecmp(TimeUnitText[i], unitStr)) { + result = (SUPPORTED_TIME_UNITS)i; + break; + } + } + + if (result != TIME_UNIT_QTY) { + time = TimeUnitSeconds[result]; + time = (unsigned long)(intModifier * time); + timeInSec = time; + } + + timeUnit = result; + timeModifier = intModifier; + + return result; +} diff --git a/src/TimeUnit.h b/src/TimeUnit.h new file mode 100755 index 0000000..94bb43d --- /dev/null +++ b/src/TimeUnit.h @@ -0,0 +1,32 @@ +#ifndef TIMEUNIT_H +#define TIMEUNIT_H + +enum SUPPORTED_TIME_UNITS { + YEARS, + MONTHS, + DAYS, + HOURS, + MINUTES, + SECONDS, + TIME_UNIT_QTY, +}; + +extern const char *TimeUnitText[]; +extern const unsigned long TimeUnitSeconds[]; + +class TimeUnit { + + public: + unsigned long GetTimeInSec(); + int GetTimeModifier(); + SUPPORTED_TIME_UNITS GetTimeUnit(); + SUPPORTED_TIME_UNITS ParseUnit(char *unitText); + + + private: + unsigned long timeInSec; + int timeModifier; + SUPPORTED_TIME_UNITS timeUnit; +}; + +#endif diff --git a/src/TimeVar.cpp b/src/TimeVar.cpp new file mode 100755 index 0000000..abb1b1e --- /dev/null +++ b/src/TimeVar.cpp @@ -0,0 +1,460 @@ +#include <cstdio> +#include <cstring> +#ifdef _WIN32 +#include <time.h> +#endif +#include <stdlib.h> +#include "Messages.h" +#include "TimeVar.h" + +#ifdef _WIN32 +int is_leap(int year); +int days_from_0(int year); +int days_from_1970(int year); +int days_from_1jan(int year, int month, int day); +time_t internal_timegm(struct tm *t); +#endif + +bool TimeVar::LoadTime(char *time) { + + int year = 0; + int month = 0; + int day = 0; + int hour = 0; + int minute = 0; + int second = 0; + + memset(¤tTime, 0, sizeof(tm)); + currentTime.tm_mday = 1; + currentTime.tm_isdst = -1; + + int num = sscanf(time, "%04d%02d%02d%02d%02d%02d", &year, &month, &day, &hour, &minute, &second); + + switch (num) { + case 6: + currentTime.tm_sec = second; + case 5: + currentTime.tm_min = minute; + case 4: + currentTime.tm_hour = hour; + case 3: + currentTime.tm_mday = day; + case 2: + currentTime.tm_mon = month - 1; + case 1: + currentTime.tm_year = year - 1900; + break; + default: + ERROR_LOGF("Unable to process time \"%s\"!", time); + return false; + } + + //This cleans up currentTime + currentTimeSec = port_timegm(¤tTime); // For portability use mktime (while setting TZ environmental variable) instead of timegm + + return true; +} + +bool TimeVar::LoadTimeExcel(char *time) { + + int year = 0; + int month = 0; + int day = 0; + int hour = 0; + int minute = 0; + int second = 0; + size_t len = strlen(time); + memset(¤tTime, 0, sizeof(tm)); + currentTime.tm_mday = 1; + currentTime.tm_isdst = -1; + + bool yearMonthDay = false; + if (time[2] != '-' && time[2] != '/') { + yearMonthDay = true; + } + + int num = 1; + char *end; + if (!yearMonthDay) { + if (len > 2) { + time[2] = ' '; // Month-Day + } + if (len > 5) { + time[5] = ' '; // Day-Year + } + if (len > 13) { + time[13] = ' '; // Hour:Minute + } + if (len > 16) { + time[16] = ' '; + } + month = strtol(time, &end, 10); + if (*end != '\0') { + num++; + day = strtol(end, &end, 10); + if (*end != '\0') { + num++; + year = strtol(end, &end, 10); + if (*end != '\0') { + num++; + hour = strtol(end, &end, 10); + if (*end != '\0') { + num++; + minute = strtol(end, &end, 10); + if (*end != '\0') { + num++; + second = strtol(end, &end, 10); + } + } + } + } + } + } else { + if (len > 4) { + time[4] = ' '; // Year-Month + } + if (len > 7) { + time[7] = ' '; // Month-Day + } + if (len > 13) { + time[13] = ' '; // Hour:Minute + } + if (len > 16) { + time[16] = ' '; + } + year = strtol(time, &end, 10); + if (*end != '\0') { + num++; + month = strtol(end, &end, 10); + if (*end != '\0') { + num++; + day = strtol(end, &end, 10); + if (*end != '\0') { + num++; + hour = strtol(end, &end, 10); + if (*end != '\0') { + num++; + minute = strtol(end, &end, 10); + if (*end != '\0') { + num++; + second = strtol(end, &end, 10); + } + } + } + } + } + } + + switch (num) { + case 6: + currentTime.tm_sec = second; + case 5: + currentTime.tm_min = minute; + case 4: + currentTime.tm_hour = hour; + case 3: + currentTime.tm_mday = day; + case 2: + currentTime.tm_mon = month - 1; + case 1: + if (year < 1900) { + if (year < 50) { + year += 2000; + } else { + year += 1900; + } + } + currentTime.tm_year = year - 1900; + break; + default: + ERROR_LOGF("Unable to process time \"%s\"!", time); + return false; + } + + //This cleans up currentTime + currentTimeSec = port_timegm(¤tTime); // For portability use mktime (while setting TZ environmental variable) instead of timegm + + return true; +} + +void TimeVar::Decrement(TimeUnit *inc) { + + switch (inc->GetTimeUnit()) { + case YEARS: + currentTime.tm_year -= inc->GetTimeModifier(); + break; + case MONTHS: + currentTime.tm_mon -= inc->GetTimeModifier(); + break; + case DAYS: + currentTime.tm_mday -= inc->GetTimeModifier(); + break; + case HOURS: + currentTime.tm_hour -= inc->GetTimeModifier(); + break; + case MINUTES: + currentTime.tm_min -= inc->GetTimeModifier(); + break; + case SECONDS: + currentTime.tm_sec -= inc->GetTimeModifier(); + break; + default: + break; // Should be __builtin_unreachable(); + } + + currentTime.tm_isdst = -1; + + //Clean up currentTime + currentTimeSec = port_timegm(¤tTime); // For portability use mktime (while setting TZ environmental variable) instead of timegm + +} + +void TimeVar::Increment(TimeUnit *inc) { + + switch (inc->GetTimeUnit()) { + case YEARS: + currentTime.tm_year += inc->GetTimeModifier(); + break; + case MONTHS: + currentTime.tm_mon += inc->GetTimeModifier(); + break; + case DAYS: + currentTime.tm_mday += inc->GetTimeModifier(); + break; + case HOURS: + currentTime.tm_hour += inc->GetTimeModifier(); + break; + case MINUTES: + currentTime.tm_min += inc->GetTimeModifier(); + break; + case SECONDS: + currentTime.tm_sec += inc->GetTimeModifier(); + break; + default: + break; // Should be __builtin_unreachable(); + } + + currentTime.tm_isdst = -1; + + //Clean up currentTime + currentTimeSec = port_timegm(¤tTime); // For portability use mktime (while setting TZ environmental variable) instead of timegm + +} + +tm *TimeVar::GetTM() { + return ¤tTime; +} + +TimeVar& TimeVar::operator=(const TimeVar &rhs) { + + memcpy(¤tTime, &rhs.currentTime, sizeof(tm)); + currentTimeSec = port_timegm(¤tTime); + return *this; +} + +bool operator==(const TimeVar& lhs, const TimeVar& rhs) { + + return lhs.currentTimeSec == rhs.currentTimeSec; + + + /*if (lhs.currentTime.tm_min != rhs.currentTime.tm_min) { + return false; + } + + if (lhs.currentTime.tm_hour != rhs.currentTime.tm_hour) { + return false; + } + + if (lhs.currentTime.tm_mday != rhs.currentTime.tm_mday) { + return false; + } + + if (lhs.currentTime.tm_year != rhs.currentTime.tm_year) { + return false; + } + + if (lhs.currentTime.tm_mon != rhs.currentTime.tm_mon) { + return false; + } + + if (lhs.currentTime.tm_sec != rhs.currentTime.tm_sec) { + return false; + } + + return true;*/ +} + +bool operator<(const TimeVar& lhs, const TimeVar& rhs) { + + return lhs.currentTimeSec < rhs.currentTimeSec; + + /* + int diff = lhs.currentTime.tm_year - rhs.currentTime.tm_year; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_mon - rhs.currentTime.tm_mon; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_mday - rhs.currentTime.tm_mday; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_hour - rhs.currentTime.tm_hour; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_min - rhs.currentTime.tm_min; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_sec - rhs.currentTime.tm_sec; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + return false;*/ +} + +bool operator<=(const TimeVar& lhs, const TimeVar& rhs) { + + return lhs.currentTimeSec <= rhs.currentTimeSec; + + + /*int diff = lhs.currentTime.tm_year - rhs.currentTime.tm_year; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_mon - rhs.currentTime.tm_mon; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_mday - rhs.currentTime.tm_mday; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_hour - rhs.currentTime.tm_hour; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_min - rhs.currentTime.tm_min; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + diff = lhs.currentTime.tm_sec - rhs.currentTime.tm_sec; + if (diff > 0) { + return false; + } else if (diff < 0) { + return true; + } + + return true;*/ + +} + +time_t TimeVar::port_timegm(struct tm *tm) { + +#ifdef _WIN32 + time_t result = mktime(tm); + struct tm *newtm = gmtime(&result); + //if (!newtm) { +// ERROR_LOGF("Got null from gmtime! %i, %i %i %i %i %i %i", result, tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + // } else { + tm->tm_year = newtm->tm_year; + tm->tm_mon = newtm->tm_mon; + tm->tm_mday = newtm->tm_mday; + tm->tm_hour = newtm->tm_hour; + tm->tm_min = newtm->tm_min; + tm->tm_sec = newtm->tm_sec; +// } + return result; //internal_timegm(tm); +#else + return timegm(tm); +#endif +} + +#ifdef WIN32 +inline int is_leap(int year) { + if(year % 400 == 0) + return 1; + if(year % 100 == 0) + return 0; + if(year % 4 == 0) + return 1; + return 0; +} +inline int days_from_0(int year) { + year--; + return 365 * year + (year / 400) - (year/100) + (year / 4); +} +inline int days_from_1970(int year) { + static const int days_from_0_to_1970 = days_from_0(1970); + return days_from_0(year) - days_from_0_to_1970; +} +inline int days_from_1jan(int year,int month,int day) { + static const int days[2][12] = + { + { 0,31,59,90,120,151,181,212,243,273,304,334}, + { 0,31,60,91,121,152,182,213,244,274,305,335} + }; + return days[is_leap(year)][month-1] + day - 1; +} + +inline time_t internal_timegm(struct tm *t) { + int year = t->tm_year + 1900; + int month = t->tm_mon; + if(month > 11) + { + year += month/12; + month %= 12; + } + else if(month < 0) + { + int years_diff = (-month + 11)/12; + year -= years_diff; + month+=12 * years_diff; + } + month++; + int day = t->tm_mday; + int day_of_year = days_from_1jan(year,month,day); + int days_since_epoch = days_from_1970(year) + day_of_year; + + time_t seconds_in_day = 3600 * 24; + time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec; + + return result; +} +#endif diff --git a/src/TimeVar.h b/src/TimeVar.h new file mode 100755 index 0000000..33b9717 --- /dev/null +++ b/src/TimeVar.h @@ -0,0 +1,30 @@ +#ifndef TIME_VAR_H +#define TIME_VAR_H + +#include <time.h> +#include "Defines.h" +#include "TimeUnit.h" + +class TimeVar { + + public: + bool LoadTime(char *time); + bool LoadTimeExcel(char *time); + void Increment(TimeUnit *inc); + void Decrement(TimeUnit *inc); + tm *GetTM(); + + TimeVar& operator=(const TimeVar &rhs); + friend bool operator==(const TimeVar& lhs, const TimeVar& rhs); + friend bool operator<(const TimeVar& lhs, const TimeVar& rhs); + friend bool operator<=(const TimeVar& lhs, const TimeVar& rhs); + + time_t currentTimeSec; + private: + tm currentTime; + + time_t port_timegm(struct tm *tm); + +}; + +#endif diff --git a/src/VCInundation.cpp b/src/VCInundation.cpp new file mode 100755 index 0000000..1635d46 --- /dev/null +++ b/src/VCInundation.cpp @@ -0,0 +1,249 @@ +#include <cstdio> +#include <cstring> +#include <cmath> +#include <stack> +#include <algorithm> +#include "DatedName.h" +#include "VCInundation.h" + +static bool TestUpstream(long nextX, long nextY, FLOW_DIR dir, GridLoc *loc); +static bool SortByHeight(GridNode *d1, GridNode *d2); + +VCInundation::VCInundation() { + +} + +VCInundation::~VCInundation() { + +} + +bool VCInundation::InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + nodes = newNodes; + if (iNodes.size() != nodes->size()) { + iNodes.resize(nodes->size()); + } + + // Fill in modelIndex in the gridNodes + size_t numNodes = nodes->size(); + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + node->modelIndex = i; + if (node->channelGridCell) { + ComputeLayers(i, node, &(iNodes[i])); + } + } + + + + InitializeParameters(paramSettings, paramGrids); + + return true; +} + +void VCInundation::ComputeLayers(size_t nodeIndex, GridNode *node, VCInundationGridNode *cNode) { + std::vector<GridNode *> upstreamNodes; + std::stack<GridNode *> walkNodes; + + walkNodes.push(node); + + while (!walkNodes.empty()) { + + //Get the next node to check off the stack + GridNode *currentN = walkNodes.top(); + walkNodes.pop(); + + upstreamNodes.push_back(currentN); + + //Lets figure out what flows into this node + for (int i = 1; i < FLOW_QTY; i++) { + GridLoc nextNode; + if (TestUpstream(currentN->x, currentN->y, (FLOW_DIR)i, &nextNode)) { + GridNode *nextN = NULL; + for (size_t nodeI = currentN->index; nodeI < nodes->size(); nodeI++) { + if (nodes->at(nodeI).x == nextNode.x && nodes->at(nodeI).y == nextNode.y) { + nextN = &nodes->at(nodeI); + break; + } + } + if (nextN && !nextN->channelGridCell) { + walkNodes.push(nextN); + } + } + } + + } + + std::sort(upstreamNodes.begin(), upstreamNodes.end(), SortByHeight); + + int upstreamCount = (int)(upstreamNodes.size()) - 1; + //printf("Found %i upstream cells for node %i, FAM is %f\n", upstreamCount, (int)nodeIndex, g_FAM->data[node->y][node->x]); + cNode->layers.reserve(upstreamNodes.size()); + for (int i = 0; i < upstreamCount; i++) { + GridNode *current = upstreamNodes[i]; + GridNode *up = upstreamNodes[i+1]; + if (nodeIndex == 54) { + printf("%i, %f\n", i, g_DEM->data[current->y][current->x]); + } + float heightDiff = g_DEM->data[up->y][up->x] - g_DEM->data[current->y][current->x]; + if (heightDiff <= 0.01) { + continue; + //heightDiff = 0.01; + } + float layerVolume = current->area * (i + 1) * heightDiff * 1000000.0; + VCILayer *layer = new VCILayer; + layer->totalVolume = layerVolume; + layer->totalArea = current->area * (i + 1) * 1000000.0; + layer->height = heightDiff; + layer->toIndex = i + 1; + cNode->layers.push_back(layer); + } + + float layerVolume = upstreamNodes[0]->area * (upstreamNodes.size()) * 1000.0 * 1000000.0; + VCILayer *layer = new VCILayer; + layer->totalVolume = layerVolume; + layer->totalArea = upstreamNodes[0]->area * (upstreamNodes.size()) * 1000000.0; + layer->height = 1000.0; + layer->toIndex = upstreamNodes.size(); + upstreamCount = (int)(upstreamNodes.size()); + cNode->gridIndicies.reserve(upstreamCount); + for (int gi = 0; gi < upstreamCount; gi++) { + cNode->gridIndicies.push_back(upstreamNodes[gi]->index); + } + cNode->layers.push_back(layer); +} + +bool VCInundation::Inundation(std::vector<float> *discharge, std::vector<float> *depth) { + + size_t numNodes = nodes->size(); + + for (size_t i = 0; i < numNodes; i++) { + depth->at(i) = 0.0; + } + + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + if (node->channelGridCell) { + VCInundationGridNode *cNode = &(iNodes[i]); + float dischargeLeft = discharge->at(i) * node->horLen; + int layerCount = (int)(cNode->layers.size()); + for (int layerI = 0; layerI < layerCount; layerI++) { + VCILayer *layer = cNode->layers[layerI]; + float volumeUsed = 0.0; + if (dischargeLeft >= layer->totalVolume) { + volumeUsed = layer->totalVolume; + dischargeLeft -= layer->totalVolume; + } else { + volumeUsed = dischargeLeft; + dischargeLeft = 0.0; + } + float height = volumeUsed / layer->totalArea; + int gridCount = (int)(layer->toIndex); + for (int gi = 0; gi < gridCount; gi++) { + depth->at(cNode->gridIndicies[gi]) += height; + } + } + } + } + + return true; +} + +void VCInundation::InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids) { + + //This pass distributes parameters + size_t numNodes = nodes->size(); + size_t unused = 0; + for (size_t i = 0; i < numNodes; i++) { + GridNode *node = &nodes->at(i); + VCInundationGridNode *cNode = &(iNodes[i]); + if (!node->gauge) { + unused++; + continue; + } + // Copy all of the parameters over + memcpy(cNode->params, (*paramSettings)[node->gauge], sizeof(float)*PARAM_VCI_QTY); + + // Deal with the distributed parameters here + GridLoc pt; + for (size_t paramI = 0; paramI < PARAM_VCI_QTY; paramI++) { + FloatGrid *grid = paramGrids->at(paramI); + if (grid && g_DEM->IsSpatialMatch(grid)) { + if (grid->data[node->y][node->x] == 0) { + grid->data[node->y][node->x] = 0.01; + } + cNode->params[paramI] *= grid->data[node->y][node->x]; + } else if (grid && grid->GetGridLoc(node->refLoc.x, node->refLoc.y, &pt)) { + if (grid->data[pt.y][pt.x] == 0) { + grid->data[pt.y][pt.x] = 0.01; + //printf("Using nodata value in param %s\n", modelParamStrings[MODEL_CREST][paramI]); + } + cNode->params[paramI] *= grid->data[pt.y][pt.x]; + } + } + + } + +} + +bool SortByHeight(GridNode *d1, GridNode *d2) { + if (g_DEM->data[d1->y][d1->x] == g_DEM->data[d2->y][d2->x]) { + return d1->index < d2->index; + } + return g_DEM->data[d1->y][d1->x] < g_DEM->data[d2->y][d2->x]; +} + +bool TestUpstream(long nextX, long nextY, FLOW_DIR dir, GridLoc *loc) { + FLOW_DIR wantDir; + + //unsigned long currentFAC = g_FAM->data[nextY][nextX]; + + switch (dir) { + case FLOW_NORTH: + nextY--; + wantDir = FLOW_SOUTH; + break; + case FLOW_NORTHEAST: + nextY--; + nextX++; + wantDir = FLOW_SOUTHWEST; + break; + case FLOW_EAST: + nextX++; + wantDir = FLOW_WEST; + break; + case FLOW_SOUTHEAST: + nextY++; + nextX++; + wantDir = FLOW_NORTHWEST; + break; + case FLOW_SOUTH: + nextY++; + wantDir = FLOW_NORTH; + break; + case FLOW_SOUTHWEST: + nextY++; + nextX--; + wantDir = FLOW_NORTHEAST; + break; + case FLOW_WEST: + nextX--; + wantDir = FLOW_EAST; + break; + case FLOW_NORTHWEST: + nextX--; + nextY--; + wantDir = FLOW_SOUTHEAST; + break; + default: + return false; + } + + if (nextX >= 0 && nextY >= 0 && nextX < g_DDM->numCols && nextY < g_DDM->numRows && g_DDM->data[nextY][nextX] == wantDir) {// && g_FAM->data[nextY][nextX] <= currentFAC) { + loc->x = nextX; + loc->y = nextY; + return true; + } + + return false; +} diff --git a/src/VCInundation.h b/src/VCInundation.h new file mode 100755 index 0000000..0b11bf3 --- /dev/null +++ b/src/VCInundation.h @@ -0,0 +1,37 @@ +#ifndef VCI_MODEL_H +#define VCI_MODEL_H + +#include "ModelBase.h" + +struct VCILayer { + float totalVolume; + float totalArea; + float height; + size_t toIndex; +}; + +struct VCInundationGridNode : BasicGridNode { + float params[PARAM_VCI_QTY]; + std::vector<long> gridIndicies; + std::vector<VCILayer *> layers; +}; + +class VCInundation : public InundationModel { + +public: + VCInundation(); + ~VCInundation(); + bool InitializeModel(std::vector<GridNode> *newNodes, std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + bool Inundation(std::vector<float> *discharge, std::vector<float> *depth); + const char *GetName() { return "vcinundation"; } + +private: + void InitializeParameters(std::map<GaugeConfigSection *, float *> *paramSettings, std::vector<FloatGrid *> *paramGrids); + void ComputeLayers(size_t nodeIndex, GridNode *node, VCInundationGridNode *cNode); + + std::vector<GridNode> *nodes; + std::vector<VCInundationGridNode> iNodes; + +}; + +#endif diff --git a/src/dream_functions.cpp b/src/dream_functions.cpp new file mode 100755 index 0000000..f6b0e43 --- /dev/null +++ b/src/dream_functions.cpp @@ -0,0 +1,904 @@ +//Simple Functions for DREAM +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <cmath> +#include "Messages.h" +#include "dream_variables.h" +#include "dream_functions.h" +#include "misc_functions.h" + +#ifdef WIN32 +#define UNIFORM_RAND ((float)(rand()) / (float)(RAND_MAX)) +#else +#define UNIFORM_RAND (drand48()) +#endif + +void InitVar(struct DREAM_Parameters *pstPar, struct DREAM_Variables **pstRUN, struct DREAM_Output **pstOutput) +{ +//Initializes important variables for use in the algorithm + int i, j, zy, zz, buffer; + float gamma, pstCb, pstWb; + float ***CRpt; + //Calculate the parameters in the exponential power density function of Box and Tiao (1973) + gamma = pstPar->Gamma; + pstCb = pstPar->Cb; + pstWb = pstPar->Wb; + CalcCbWb(&gamma, &pstCb, &pstWb); + pstPar->Cb = pstCb; + pstPar->Wb = pstWb; + + buffer = 10; //Matlab version allows arrays to increase size after pre-allocation + + //Allocate Memory for DREAM run variables + *pstRUN = (struct DREAM_Variables *)malloc(sizeof(struct DREAM_Variables)); + //Derive the number of elements in the output file + (*pstRUN)->Nelem = floorf(pstPar->ndraw/pstPar->seq) + 1; + INFO_LOGF("Nelem is %i (%f), ndraw is %li", (*pstRUN)->Nelem, floorf(1.25 * (float)((*pstRUN)->Nelem)), pstPar->ndraw); + //Allocate the array that contains the history of the log_density of each chain + allocate2D(&(*pstRUN)->hist_logp, (*pstRUN)->Nelem - 1 + buffer * 2, pstPar->seq+1); + //Allocate Memory for DREAM output + *pstOutput = (struct DREAM_Output *)malloc(sizeof(struct DREAM_Output)); + //Initialize output information -- AR + allocate2D(&(*pstOutput)->AR, (*pstRUN)->Nelem + buffer, 2); + (*pstOutput)->AR[1][1] = pstPar->seq - 1; (*pstOutput)->AR[1][2] = pstPar->seq - 1; + //Initialize output information -- R statistic + allocate2D(&(*pstOutput)->R_stat, floorf((*pstRUN)->Nelem / pstPar->steps)+buffer, pstPar->n + 1); + + //Outlier + allocate2D(&(*pstOutput)->outlier, pstPar->ndraw + 1, 2); + + //if pCR = 'Update' + //Calculate multinomial probabilities of each of the nCR CR values + allocate2D(&(*pstRUN)->pCR, 1, pstPar->nCR); + for (j = 0;j < pstPar->nCR; j++) + { + (*pstRUN)->pCR[0][j] = 1.0f / (float)(pstPar->nCR); + } + //Calculate the actual CR values based on p + allocate2D(&(*pstRUN)->CR, pstPar->seq, pstPar->steps); + (*pstRUN)->lCR = (float*)malloc(pstPar->nCR*sizeof(float)); + CRpt = &(*pstRUN)->CR; + GenCR(&pstPar,&(*pstRUN)->pCR, &CRpt); + //Initialize output information -- N_CR + allocate2D(&(*pstOutput)->CR, floorf((*pstRUN)->Nelem / pstPar->steps) + buffer, pstPar->nCR + 1); + //If save_in_memory == 'yes', malloc 3D array Sequences + (*pstRUN)->Sequences = (float ***)malloc(floorf(1.25 * (float)((*pstRUN)->Nelem))*sizeof(float **)); + for (i=0;i < (floorf(1.25 * (float)((*pstRUN)->Nelem)));i++) + { + (*pstRUN)->Sequences[i] = (float **)malloc((pstPar->n + 2)*sizeof(float *)); + for (j=0;j < (pstPar->n + 2);j++) + { + (*pstRUN)->Sequences[i][j] = (float *)malloc(pstPar->seq * sizeof(float)); + memset((*pstRUN)->Sequences[i][j], 0, pstPar->seq * sizeof(float)); + } + } + MEMORYCHECK((*pstRUN)->Sequences,"ERROR at InitVar: Out of Memory!! 3D array not allocated.\n"); + //Generate the Table with JumpRates (dependent on number of dimensions and number of pairs) + allocate2D(&(*pstRUN)->Table_JumpRate, pstPar->n, pstPar->DEpairs); + for (zz=0;zz < pstPar->DEpairs;zz++) + { + for (zy=0;zy < pstPar->n;zy++) + { + (*pstRUN)->Table_JumpRate[zy][zz] = 2.38f / sqrt(2.0f * (float)(zz + 1) * (float)(zy + 1)); + } + } + //Initialize Iter and counter + (*pstRUN)->Iter = pstPar->seq; + (*pstRUN)->counter = 2; + (*pstRUN)->iloc = 1; + (*pstRUN)->teller = 2; + (*pstRUN)->new_teller = 1; + //Change MCMCPar.steps to make sure to get nice iteration numbers in first loop + pstPar->steps = pstPar->steps - 1; +} + +void CalcCbWb(float *beta, float *pCb, float *pWb) +{ + /*This function calculates the parameters for the exponential power density + Equation [20] paper by Thiemann et al. WRR 2001, Vol 37, No 10, 2521-2535*/ + float A1, A2; + A1 = expf(lgammaf(3*(1+*beta)/2)); + A2 = expf(lgammaf((1+*beta)/2)); + *pCb = powf((A1/A2),(1/(1+*beta))); + *pWb = sqrtf(A1)/((1+*beta)*powf(A2,(1.5))); +} + +void GenCR(struct DREAM_Parameters **ppPar, float ***pppCR, float ****ptCR) +{ + //Generates CR values based on current probabilities + int cont, idx, i_start, i_end, i, j, zz, sumL, *ptL, *ptr; + int L[(*ppPar)->nCR], L2[(*ppPar)->nCR + 1], r[(*ppPar)->seq * (*ppPar)->steps]; + float CRarray[(*ppPar)->seq * (*ppPar)->steps]; + ptL = &L[0]; + ptr = &r[0]; + //How many candidate points for each crossover value? + multrnd(&ptL, (*ppPar)->seq * (*ppPar)->steps, pppCR, (*ppPar)->nCR, 1); + sumL = 0; + for (i=0;i <((*ppPar)->nCR + 1);i++) + { + if (i != 0) + { + sumL = sumL + L[i-1]; + //printf("i %i %i\n", i, L[i-1]); + } + L2[i] = sumL; + } + //Then select which candidate points are selected with what CR + randperm(&ptr, (*ppPar)->seq * (*ppPar)->steps); + //Then generate CR values for each chain + for (zz=0;zz < (*ppPar)->nCR;zz++) + { + i_start = L2[zz]; + i_end = L2[zz+1]; + //printf("start %i, end %i\n", i_start, i_end); + for (i=i_start;i < i_end;i++) + { + idx = r[i]-1; + CRarray[idx] = (float) (zz+1) / (float)((*ppPar)->nCR); + //printf("blah %i %i %f\n", zz+1, (*ppPar)->nCR, CRarray[idx]); + } + } + //Reshape CR 1D array into 2D array of "(*ppPar)->seq" rows and "(*ppPar)->steps" columns + cont = 0; + for (j=0;j < (*ppPar)->steps;j++) + { + for (i=0;i < (*ppPar)->seq;i++) + { + (**ptCR)[i][j] = CRarray[cont]; + cont = cont + 1; + } + } + } + +void multrnd(int **X, int n, float ***p, int ncols, int m) +{ + //MULTRND Multinomial random sequence of m simulations of k outcomes with p probabiltites + // in n trials. + int i, j, in; + float sums; + float o[n], r[n], s[ncols]; + sums = 0; + //P = sumarray(**p,1,ncols); + for (i=0;i < m;i++) + { + for (in=0;in < n;in++) + { + o[in] = 1; //assign 1 to every element of array o + r[in] = UNIFORM_RAND; //generate Uniformly distributed pseudorandom numbers [0 1) + } + //cumulative sum + for (in=0;in < ncols;in++) + { + sums = sums + (*p)[0][in]; + s[in] = sums; + //printf("index %i s %f\n", in, sums); + //Initialize Ouput Vector + (*X)[in] = 0; + } + for (j=0;j < ncols;j++) + { + for (in=0;in < n;in++) + { + if (s[j] < r[in]) + { + o[in] = o[in] + 1; + } + } + } + for (j=0;j < ncols;j++) + { + for (in=0;in < n;in++) + { + if (o[in] == j+1) + { + //X - multinomial random deviates (default output). + (*X)[j] = (*X)[j] + 1; + //printf("X is %i o is %f %i\n", (*X)[j], o[in], j); + } + } + //Y - multinomial probabilities of the generated random deviates (optional output) + //Y[j] = (float)((*X)[j]) / (float)(n); + } + } + } + +void LHSU(float ***s, int nvar, float *xmax, float *xmin, int nsample) +{ + int i, j, *pidx, idx[nsample]; + float P[nsample], ran[nsample][nvar]; + float nsamplef = (float)(nsample); + //Initialize array ran with random numbers + for (i=0;i < nsample;i++) + { + for (j=0;j < nvar;j++) + { + ran[i][j] = UNIFORM_RAND; + } + } + //Now fill s + pidx = &idx[0]; + for (j=0;j < nvar;j++) + { + randperm(&pidx,nsample); + for (i=0;i < nsample;i++) + { + P[i] = ((float)(idx[i]) - ran[i][j])/nsamplef; + (*s)[i][j] = xmin[j] + P[i]*(xmax[j]-xmin[j]); + } + } + } + +void InitSequences(float **X, float ***Sequences, struct DREAM_Parameters *MCMCPar) +{ + int qq, kk; + //Initialize sequences + for (kk=0;kk < MCMCPar->n+2;kk++) + { + for (qq=0;qq < MCMCPar->seq;qq++) + { + Sequences[0][kk][qq] = X[qq][kk]; + } + } + } + +void Gelman(float **R_Stat, int R_Stat_Index, float ***Sequences, int numSamples, int numParams, int numChains, int start_loc) { + // in = number of samples + // m = number of parameters + // ip = number of sequences + + //Calculates the R-statistic convergence diagnostic + int iSamples, iParams, iChains; + float **meanSeq; + float **varSeq, *vararray, *B, *W, *sigma2; + float numChainsf = (float)numChains; + float numSamplesf = (float)numSamples; +if (numSamples < 10) { + //Set the R-statistic to a large value + for (iParams = 0; iParams < numParams; iParams++) { + R_Stat[R_Stat_Index][iParams + 1] = -2; + } +} else { + //Step 1: Determine the sequence means + allocate2D(&meanSeq, numChains, numParams); + MEMORYCHECK(meanSeq, "at Gelman: Sequences Mean array not allocated\n"); + vararray = (float*)malloc(numSamples * sizeof(float)); + MEMORYCHECK(vararray, "at Gelman: Variance array not allocated\n"); + allocate2D(&varSeq, numChains, numParams); + MEMORYCHECK(varSeq, "at Gelman: varSeq array not allocated\n"); + for (iChains = 0; iChains < numChains; iChains++) { // For each sequence + for (iParams = 0; iParams < numParams; iParams++) { // For each parameter + for (iSamples = 0; iSamples < numSamples - 1; iSamples++) { // For each sample + vararray[iSamples] = Sequences[iSamples + start_loc][iParams][iChains]; + } + meanSeq[iChains][iParams] = meanvar(vararray, numSamples - 1, MVOP_MEAN); + varSeq[iChains][iParams] = meanvar(vararray, numSamples - 1, MVOP_VAR); + } + } + free(vararray); + + //Step 1: Determine the variance between the sequence means + vararray = (float*)malloc(numChains * sizeof(float)); + MEMORYCHECK(vararray, "at Gelman: Variance array not allocated\n"); + B = (float*)malloc(numParams * sizeof(float)); + MEMORYCHECK(B, "at Gelman: B array not allocated\n"); + for (iParams = 0; iParams < numParams; iParams++) { // for each parameter + for (iChains = 0; iChains < numChains; iChains++) { // for each sequence + vararray[iChains] = meanSeq[iChains][iParams]; + } + B[iParams] = numSamplesf * meanvar(vararray, numChains, MVOP_VAR); + } + free(vararray); + + //Step 2: Compute the variance of the various sequences + + //Step 2: Calculate the average of the within sequence variances + W = (float*)malloc(numParams * sizeof(float)); + MEMORYCHECK(W, "at Gelman: W array not allocated\n"); + vararray = (float*)malloc(numChains * sizeof(float)); + MEMORYCHECK(vararray, "at Gelman: Variance array not allocated\n"); + for (iParams = 0; iParams < numParams; iParams++) { + for (iChains = 0; iChains < numChains; iChains++) { + vararray[iChains] = varSeq[iChains][iParams]; + } + W[iParams] = meanvar(vararray, numChains, MVOP_MEAN); + } + free(vararray); + + //Step 3: Estimate the target variance + sigma2 = (float*)malloc(numParams * sizeof(float)); + MEMORYCHECK(sigma2, "at Gelman: sigma2 array not allocated\n"); + for (iParams = 0; iParams < numParams; iParams++) { + sigma2[iParams] = ((numSamplesf - 1)/numSamplesf) * W[iParams] + (1/numSamplesf) * B[iParams]; + } + + //Step 5: Compute the R-statistic + for (iParams = 0; iParams < numParams; iParams++) { + if (sigma2[iParams] == 0) { + R_Stat[R_Stat_Index][iParams + 1] = 1.0; + } else { + R_Stat[R_Stat_Index][iParams + 1] = sqrt((numChainsf + 1)/numChainsf * sigma2[iParams]/W[iParams] - (numSamplesf-1)/numChainsf/numSamplesf); + } + } + //Deallocating Memory + free(sigma2); + free(B); + free(W); + deallocate2D(&meanSeq, numChains); + deallocate2D(&varSeq, numChains); +} +} + +void GetLocation(float **x_old, float *p_old, float *log_p_old, float **X, struct DREAM_Parameters *MCMCPar) +{ + //Extracts the current location and density of the chain + + int i,j; + + //First get the current location + for (i=0;i < MCMCPar->seq;i++) + { + for (j=0;j < MCMCPar->n;j++) + { + x_old[i][j] = X[i][j]; + } + } + + //Then get the current density + for (i=0;i < MCMCPar->seq;i++) + { + p_old[i] = X[i][MCMCPar->n]; + } + + //Then get the current logdensity + for (i=0;i < MCMCPar->seq;i++) + { + log_p_old[i] = X[i][MCMCPar->n+1]; + } + } + +void DEStrategy(int *DEversion, struct DREAM_Parameters *MCMCPar) +{ + //Determine which sequences to evolve with what DE strategy + int qq, i, j, zend = 0; + float *p_pair, *Z; + //Determine probability of selecting a given number of pairs + p_pair = (float*)malloc((MCMCPar->DEpairs + 1)*sizeof(float)); + MEMORYCHECK(p_pair,"ERROR at DEStrategy: Out of Memory!! p_pair not allocated.\n"); + p_pair[0] = 0; + for (i=1;i < MCMCPar->DEpairs + 1;i++) + { + p_pair[i] = p_pair[i-1] + 1.0 / (float)(MCMCPar->DEpairs); + } + //Generate a random number between 0 and 1 + Z = (float*)malloc(MCMCPar->seq*sizeof(float)); + MEMORYCHECK(Z,"ERROR at DEStrategy: Out of Memory!! Z not allocated.\n"); + for (i=0;i < MCMCPar->seq;i++) + { + Z[i] = UNIFORM_RAND; + } + //Select number of pairs + for (qq=0;qq < MCMCPar->seq;qq++) + { + for (j=0;j < MCMCPar->DEpairs + 1;j++) + { + if (Z[qq] > p_pair[j]) + { + zend = j + 1; + } + } + DEversion[qq] = zend; + } + free(p_pair); + free(Z); + } + +void offde(float **x_new, float **x_old, float **X, float **CR, struct DREAM_Parameters *MCMC, float **Table_JumpRate, struct Model_Input *Input, const char *BHandling, float *R2, const char *DR) { + //Generates offspring using METROPOLIS HASTINGS monte-carlo markov chain + int i,j,qq; + float **eps, D[MCMC->seq][MCMC->n], noise_x[MCMC->seq][MCMC->n], delta_x[MCMC->seq][MCMC->n]; + int *DEversion = NULL, *permarray = NULL, tt[MCMC->seq-1][MCMC->seq], idx[MCMC->seq-1], ii[MCMC->seq], *rr; + int NrDim, p_i[MCMC->n], *pp_i;; + float rndnum, Jump_Rate, delta[MCMC->n], temp_delta[MCMC->n]; + + memset(delta, 0, MCMC->n * sizeof(float)); + + //Generate ergodicity term + allocate2D(&eps, MCMC->seq, MCMC->n); + nrandn(eps,MCMC->seq,MCMC->n); + for (i = 0; i < MCMC->seq; i++) { + for (j = 0; j < MCMC->n; j++) { + eps[i][j] = 1e-6 * eps[i][j]; // * (Input->ParRangeMax[j] - Input->ParRangeMin[j]); + //Generate uniform random numbers for each chain to determine which dimension to update + D[i][j] = UNIFORM_RAND; + + //Ergodicity for each individual chain + noise_x[i][j] = MCMC->eps * (2 * UNIFORM_RAND - 1); + + //Initialize the delta update to zero + delta_x[i][j] = 0; + } + ii[i] = 1; //Define ii + } + + //If not a delayed rejection step --> generate proposal with DE + if (strcmp(DR,"No")== 0) { + //Determine which sequences to evolve with what DE strategy + DEversion = (int*)malloc(MCMC->seq*sizeof(int)); + MEMORYCHECK(DEversion,"ERROR at offde: Out of Memory!! DEversion not allocated.\n"); + DEStrategy(DEversion, MCMC); + + //Generate series of permutations of chains + permarray = (int*)malloc((MCMC->seq-1)*sizeof(int)); + MEMORYCHECK(permarray,"ERROR at offde: Out of Memory!! permarray not allocated.\n"); + for (i=0;i < MCMC->seq;i++) { + randperm(&permarray, MCMC->seq-1); + for (j=0;j < MCMC->seq-1;j++) { + tt[j][i] = permarray[j]-1; + } + } + + //Each chain evolves using information from other chains to create offspring + for (qq=0;qq < MCMC->seq;qq++) { + //Remove from ii current member as an option + ii[qq] = 0; + j = 0; + for (i=0;i < MCMC->seq;i++) { + if (ii[i] > 0) { + idx[j] = i; + j = j + 1; + } + } + + //randomly select two members of ii that have value == 1 + rr = (int*)malloc(2 * DEversion[qq] * sizeof(int)); + for (i=0;i < 2 * DEversion[qq];i++) { + rr[i] = idx[tt[i][qq]]; + } + + //--- WHICH DIMENSIONS TO UPDATE? DO SOMETHING WITH CROSSOVER ---- + NrDim = 0; + for (i=0;i < MCMC->n;i++) { + if (D[qq][i] > (1 - CR[qq][0])) { + //printf("Updating dim %i %f %f\n", i, D[qq][i], (1 - CR[qq][0])); + p_i[NrDim] = i; + NrDim++; //Determine the number of dimensions that are going to be updated + } + } + + //Update at least one dimension + if (NrDim == 0) { + pp_i = &p_i[0]; + randperm(&pp_i, MCMC->n); + NrDim = 1; + } + + //Determine the associated JumpRate and compute the jump + rndnum = UNIFORM_RAND; + if (rndnum < 0.8) { + //Lookup Table + Jump_Rate = Table_JumpRate[NrDim-1][DEversion[qq]-1]; + + //Produce the difference of the pairs used for population evolution + for (i=0;i < DEversion[qq];i++) { + for (j=0;j < MCMC->n;j++) { + temp_delta[j] = X[rr[i]][j] - X[rr[DEversion[qq]+i]][j]; + delta[j] = delta[j] + temp_delta[j]; + } + } + + //Then fill update the dimension + for (i=0;i < NrDim;i++) { + delta_x[qq][p_i[i]] = (1 + noise_x[qq][p_i[i]]) * Jump_Rate * delta[p_i[i]]; + //printf("delta_x(%i, %i) %f %f %f %f\n", qq, p_i[i], delta_x[qq][p_i[i]], (1 + noise_x[qq][p_i[i]]), Jump_Rate, delta[p_i[i]]); + //checker[j] = powf(delta_x[qq][j],2); + } + } else { + //Set the JumpRate to 1 and overwrite CR and DEversion + Jump_Rate = 1; + CR[qq][0] = 1; + + //Compute delta from one pair + for (j=0;j < MCMC->n;j++) { + delta[j] = X[rr[0]][j] - X[rr[1]][j]; + } + + //Now jumprate to facilitate jumping from one mode to the other in all dimensions + for (j=0;j < MCMC->n;j++) { + delta_x[qq][j] = Jump_Rate * delta[j]; + //printf("delta_x1(%i, %i) %f\n", qq, j, delta_x[qq][j]); + //checker[j] = powf(delta_x[qq][j],2); + } + } + ii[qq] = 1; + free(rr); + } + } //if (strcmp(DR,"No")== 0) + //Update x_old with delta_x and eps + for (i=0;i < MCMC->seq;i++) + { + for (j=0;j < MCMC->n;j++) + { + x_new[i][j] = x_old[i][j] + delta_x[i][j] + eps[i][j]; + } + } + + //Do boundary handling -- what to do when points fall outside bound + if (strcmp(BHandling,"Reflect") == 0) + { + ReflectBounds(x_new, Input, MCMC->seq, MCMC->n); + } + + if (strcmp(BHandling,"Bound") == 0) + { + printf("ERROR at offde: This option has not been implemented2.\n"); + exit(1); + } + + if (strcmp(BHandling,"Fold") == 0) + { + printf("ERROR at offde: This option has not been implemented3.\n"); + exit(1); + } + + free(DEversion); + free(permarray); + deallocate2D(&eps, MCMC->seq); +} + +void ReflectBounds(float **x_new, struct Model_Input *Input, int nmbOfIndivs, int Dim) +{ + //Checks the bounds of the parameters + int i,j; + //Now check whether points are within bond + for (i=0;i < nmbOfIndivs;i++) + { + for (j=0;j < Dim;j++) + { + if (x_new[i][j] < Input->ParRangeMin[j]) + { + x_new[i][j] = 2 * Input->ParRangeMin[j] - x_new[i][j]; + } + + if (x_new[i][j] > Input->ParRangeMax[j]) + { + x_new[i][j] = 2 * Input->ParRangeMax[j] - x_new[i][j]; + } + + //Now double check if all elements are within bounds + if (x_new[i][j] < Input->ParRangeMin[j]) + { + x_new[i][j] = Input->ParRangeMin[j] + UNIFORM_RAND*(Input->ParRangeMax[j] - Input->ParRangeMin[j]); + } + + if (x_new[i][j] > Input->ParRangeMax[j]) + { + x_new[i][j] = Input->ParRangeMin[j] + UNIFORM_RAND*(Input->ParRangeMax[j] - Input->ParRangeMin[j]); + } + } + } + } + +void metrop(float **newgen, float *alpha, float *accept, float **x, float **p_x, float *log_p_x, float **x_old, float *p_old, float *log_p_old, struct Model_Input *pointerInput, struct DREAM_Parameters *pointerMCMC, int option) +{ + //Metropolis rule for acceptance or rejection + int i, j, NrChains; + float pre_alpha, Z; + //Calculate the number of Chains + NrChains = pointerMCMC->seq; + + //First set newgen to the old positions in X + for (i=0;i < pointerMCMC->seq;i++) + { + for (j=0;j < pointerMCMC->n;j++) + { + newgen[i][j] = x_old[i][j]; + } + newgen[i][pointerInput->nPar] = p_old[i]; + newgen[i][pointerInput->nPar+1] = log_p_old[i]; + } + + //-------------------- Now check the various options ---------------------- + if (option == 1) + { + for (i=0;i < NrChains;i++) { + pre_alpha = (p_x[i][0]- 1.0) / (p_old[i] - 1.0); + //printf("p %f %i %f %f\n", pre_alpha, i, p_x[i][0], p_old[i]); + if (pre_alpha < 1.0) { + alpha[i] = pre_alpha; + } else { + alpha[i] = 1.0; + } + } + + } + + if ((option == 2) || (option == 4)) //Lnp probability evaluation + { + printf("ERROR at metrop: This option has not been implemented.\n"); + exit(1); + } + + if (option == 3) //SSE probability evaluation + { + for (i=0;i < NrChains;i++) + { + float expt = (float)(pointerInput->MaxT); + expt *= -1; + expt *= ((1 + pointerMCMC->Gamma)/2); + pre_alpha = powf(((p_x[i][0] - 1.0)/(p_old[i] - 1.0)), expt); + //pre_alpha = powf((p_x[i][0]/p_old[i]), expt); + //printf("Weee %f %f %f %f\n", pre_alpha, expt, p_x[i][0], p_old[i]); + if (pre_alpha < 1.0) + { + alpha[i] = pre_alpha; + } + else + { + alpha[i] = 1.0; + } + } + } + + if (option == 5) //Similar as 3 but now weighted with Measurement.Sigma + { + printf("ERROR at metrop: This option has not been implemented.\n"); + exit(1); + } + + //Generate random numbers + for (i=0;i < NrChains;i++) + { + Z = UNIFORM_RAND; + //printf("a %f %f %i\n", Z, alpha[i], i); + if (Z < alpha[i]) //Find which alpha's are greater than Z + { + accept[i] = 1; //indicate that these chains have been accepted + for (j=0;j < pointerMCMC->n;j++) + { + newgen[i][j] = x[i][j]; //update these chains + } + //update these chains + newgen[i][pointerInput->nPar] = p_x[i][0]; + newgen[i][pointerInput->nPar+1] = log_p_x[i]; + } + } + } + +void CalcDelta(float *delta_tot, struct DREAM_Parameters *MCMC, float *delta_normX, struct DREAM_Variables *RUNvar, int gnum) +{ + //Calculate total normalized Euclidean distance for each crossover value + int zz, i; + + //Derive sum_p2 for each different CR value + for (zz=0;zz < MCMC->nCR;zz++) + { + //Find which chains are updated with zz/MCMCPar.nCR + for (i=0;i < MCMC->seq;i++) + { + float testVal = (float)(zz + 1) / (float)(MCMC->nCR); + if (RUNvar->CR[i][gnum] == testVal) + { + //Add the normalized squared distance tot the current delta_tot; + delta_tot[zz] = delta_tot[zz] + delta_normX[i]; + } + } + } + } + +void AdaptpCR(struct DREAM_Variables *RUNvar, struct DREAM_Parameters *MCMC, float *delta_tot) +{ + //Updates the probabilities of the various crossover values + + float **CRvector, sumpCR; + int i, zz, cont; + + //Make CR to be a single vector + reshape(RUNvar->CR, MCMC->seq, MCMC->steps, &CRvector, 1, MCMC->seq * MCMC->steps); + + //Determine lCR + for (zz=0;zz < MCMC->nCR;zz++) + { + //Determine how many times a particular CR value is used + cont = 0; + for (i=0;i < MCMC->seq * MCMC->steps;i++) + { + float testVal = (float)(zz + 1) / (float)(MCMC->nCR); + if (CRvector[0][i] == testVal) + { + cont = cont + 1; + } + } + //This is used to weight delta_tot + RUNvar->lCR[zz] = RUNvar->lCR[zz] + cont; + } + + //Adapt pCR using information from averaged normalized jumping distance + for (i=0;i < MCMC->nCR;i++) + { + RUNvar->pCR[0][i] = (float)(MCMC->seq) * (delta_tot[i]/RUNvar->lCR[i]) / sumarray(&delta_tot[0], MCMC->nCR, 1); +} + + //Normalize pCR + sumpCR = sumarray(&RUNvar->pCR[0][0], 1, MCMC->nCR); + for (i=0;i < MCMC->nCR;i++) + { + RUNvar->pCR[0][i] = RUNvar->pCR[0][i] / sumpCR; + INFO_LOGF("pCR %i %f %f %f %f", i, RUNvar->pCR[0][i], delta_tot[i], RUNvar->lCR[i], sumarray(&delta_tot[0], MCMC->nCR, 1)); + } + deallocate2D(&CRvector,1); + } + +void RemOutLierChains(float **X, struct DREAM_Variables *RUNvar, struct DREAM_Parameters *MCMC, struct DREAM_Output *output) +{ + //Finds outlier chains and removes them when needed + int i, j, cont, idx_start, idx_end, arr_size, Nid, *chain_id, qq, r_idx = 0; + float *mean_hist_logp, *col_array, Q1, Q3, IQR, UpperRange; + + //Determine the number of elements of L_density + idx_end = RUNvar->Nelem - 1; + idx_start = floorf(0.5*idx_end); + arr_size = idx_end - idx_start + 1; + + col_array = (float*)malloc(arr_size*sizeof(float)); + MEMORYCHECK(col_array, "ERROR at RemOutLierChains: Out of Memory!! col_array not allocated.\n") + mean_hist_logp = (float*)malloc(MCMC->seq*sizeof(float)); + MEMORYCHECK(mean_hist_logp, "ERROR at RemOutLierChains: Out of Memory!! mean_hist_logp not allocated.\n") + //Then determine the mean log density of the active chains + for (j=0;j < MCMC->seq; j++) + { + cont = 0; + for (i=idx_start; i < idx_end; i++) + { + col_array[cont] = RUNvar->hist_logp[i][j]; + cont++; + } + mean_hist_logp[j] = meanvar(col_array, arr_size, MVOP_MEAN); + } + + //Initialize chain_id and Nid + Nid = 0; + + // Check whether any of these active chains are outlier chains + chain_id = (int*)malloc(MCMC->seq*sizeof(int)); + MEMORYCHECK(chain_id, "ERROR at RemOutLierChains: Out of Memory!! chain_id not allocated.\n"); + if (strcmp(MCMC->outlierTest, "IQR_Test") == 0) + { + //Derive the upper and lower quantile of the data + Q1 = percentile(mean_hist_logp, MCMC->seq, 75); + Q3 = percentile(mean_hist_logp, MCMC->seq, 25); + + //Derive the Inter quartile range + IQR = Q1 - Q3; + + //Compute the upper range -- to detect outliers + UpperRange = Q3 - 2 * IQR; + + //See whether there are any outlier chains + cont = 0; + for (i=0;i < MCMC->seq;i++) + { + if (mean_hist_logp[i] < UpperRange) + { + chain_id[cont] = i; + cont = cont + 1; + } + } + + Nid = cont; + } + + if (strcmp(MCMC->outlierTest, "Grubbs_test") == 0) + { + printf("ERROR at RemOutLierChains: Grubbs_test option has not been implemented\n"); + exit(1); + } + + if (strcmp(MCMC->outlierTest, "Mahal_test") == 0) + { + printf("ERROR at RemOutLierChains: Mahal_test option has not been implemented\n"); + exit(1); + } + + if (Nid > 0) + { + INFO_LOGF("Killing outlier chain!! %i", RUNvar->Iter); + //Loop over each outlier chain + for (qq=0;qq < Nid;qq++) + { + //Draw random other chain -- cannot be the same as current chain + for (i=0;i < MCMC->seq;i++) + { + if (mean_hist_logp[i] == meanvar(mean_hist_logp, MCMC->seq, MVOP_MAX)) + { + r_idx = i; + break; + } + } + + //Added -- update hist_logp -- chain will not be considered as an outlier chain then + for (i=0;i < RUNvar->Nelem - 1;i++) + { + RUNvar->hist_logp[i][chain_id[qq]] = RUNvar->hist_logp[i][r_idx]; + } + + //Jump outlier chain to r_idx -- Sequences + //Jump outlier chain to r_idx -- X + for (i=0;i < MCMC->n + 2;i++) + { + RUNvar->Sequences[0][i][chain_id[qq]] = X[r_idx][i]; + X[chain_id[qq]][i] = X[r_idx][i]; + } + + //Add to chainoutlier + output->outlier[RUNvar->Iter][0] = RUNvar->Iter; + output->outlier[RUNvar->Iter][1] = chain_id[qq]; + } + } + + free(col_array); + free(mean_hist_logp); + free(chain_id); + } + +void GenParSet(float **ParSet, struct DREAM_Variables *RUNvar, int post_Sequences, struct DREAM_Parameters *MCMC, FILE *fid, float *bestParams) +{ + int qq, i, j, cont = 0, num; + float **parset, **sorted; + //Generates ParSet + //If save in memory -> No -- ParSet is empty + //if (post_Sequences == 1) + //{ + //Do nothing + //} + //else + //{ + //If save in memory -> Yes -- ParSet derived from all sequences + allocate2D(&parset, post_Sequences * MCMC->seq, MCMC->n+3); + allocate2D(&sorted, post_Sequences * MCMC->seq, MCMC->n+3); + cont = 0; + for (qq=0;qq < MCMC->seq;qq++) + { + num = 0; + for (i=0;i < post_Sequences;i++) + { + for (j=0;j < MCMC->n+2;j++) + { + parset[cont][j] = RUNvar->Sequences[i][j][qq]; + } + parset[cont][MCMC->n+2] = num; + cont = cont + 1; + num = num + 1; + } + } + //} + //Sort according to MATLAB DREAM + sortrows(parset, cont, MCMC->n+3, MCMC->n+2, sorted); + + //Sort so the best parameter set is the last + sortrows(sorted, cont, MCMC->n+3, MCMC->n, parset); + //Write to disk + for (i=0;i < (MCMC->seq * post_Sequences);i++) + { + for (j=0;j < MCMC->n+2;j++) + { + //ParSet[i][j] = sorted[i][j]; + ParSet[i][j] = parset[i][j]; + if (j == MCMC->n+1) + { + fprintf(fid, "%f\n", ParSet[i][j]); + } + else + { + fprintf(fid, "%f,", ParSet[i][j]); + } + } + } + i = (MCMC->seq * post_Sequences) - 1; + for (j = 0; j < MCMC->n; j++) { + bestParams[j] = ParSet[i][j]; + } + + deallocate2D(&parset, post_Sequences * MCMC->seq); + deallocate2D(&sorted, post_Sequences * MCMC->seq); + } diff --git a/src/dream_functions.h b/src/dream_functions.h new file mode 100755 index 0000000..0eb225e --- /dev/null +++ b/src/dream_functions.h @@ -0,0 +1,20 @@ +#ifndef DREAM_FUNCTIONS_H +#define DREAM_FUNCTIONS_H +void dream(struct DREAM_Parameters *pointerMCMC, struct Model_Input *pointerInput); +void CalcCbWb(float *beta, float *pCb, float *pWb); +void InitVar(struct DREAM_Parameters *pstPar, struct DREAM_Variables **ptRUN, struct DREAM_Output **pstOutput); +void GenCR(struct DREAM_Parameters **ppPar, float ***pppCR, float ****ptCR); +void multrnd(int **X, int n, float ***p, int ncols, int m); +void LHSU(float ***s, int nvar, float *xmax, float *xmin, int nsample); +void InitSequences(float **X, float ***Sequences, struct DREAM_Parameters *MCMCPar); +void Gelman(float **R_Stat, int R_Stat_Index, float ***Sequences, int numSamples, int numParams, int numChains, int start_loc); +void GetLocation(float **x_old, float *p_old, float *log_p_old, float **X, struct DREAM_Parameters *MCMCPar); +void offde(float **x_new, float **x_old, float **X, float **CR, struct DREAM_Parameters *MCMC, float **Table_JumpRate, struct Model_Input *Input, const char *BHandling, float *R2, const char *DR); +void DEStrategy(int *DEversion, struct DREAM_Parameters *MCMCPar); +void ReflectBounds(float **x_new, struct Model_Input *Input, int nmbOfIndivs, int Dim); +void metrop(float **newgen, float *alpha, float *accept, float **x, float **p_x, float *log_p_x, float **x_old, float *p_old, float *log_p_old, struct Model_Input *pointerInput, struct DREAM_Parameters *pointerMCMC, int option); +void CalcDelta(float *delta_tot, struct DREAM_Parameters *MCMC, float *delta_normX, struct DREAM_Variables *RUNvar, int gnum); +void AdaptpCR(struct DREAM_Variables *RUNvar, struct DREAM_Parameters *MCMC, float *delta_tot); +void RemOutLierChains(float **X, struct DREAM_Variables *RUNvar, struct DREAM_Parameters *MCMC, struct DREAM_Output *output); +void GenParSet(float **ParSet, struct DREAM_Variables *RUNvar, int post_Sequences, struct DREAM_Parameters *MCMC, FILE *fid, float *bestParams); +#endif diff --git a/src/dream_variables.h b/src/dream_variables.h new file mode 100755 index 0000000..ef1cfd9 --- /dev/null +++ b/src/dream_variables.h @@ -0,0 +1,71 @@ +#ifndef DREAM_VARIABLES_H +#define DREAM_VARIABLES_H + +#define MEMORYCHECK(x, m) if (x == NULL) { printf("%s", m); exit(1); } + +struct DREAM_Parameters + { + int n; + int seq; + unsigned long ndraw; + int nCR; + float Gamma; + int DEpairs; + int steps; + float eps; + char outlierTest[10]; + float Cb; + float Wb; + }; +struct DREAM_Variables +{ + int Nelem; + float **hist_logp; + float **pCR; + float **CR; + float *lCR; + float ***Sequences; + float **Table_JumpRate; + float *Reduced_Seq; + unsigned int Iter; + int counter; + int teller; + int new_teller; + int iloc; + }; +struct DREAM_Output +{ + float **AR; + float **outlier; + float **R_stat; + float **CR; + }; +struct DREAM_Input +{ + char pCR[10]; + char reduced_sample_collection[4]; + char InitPopulation[10]; + char BoundHandling[10]; + char save_in_memory[4]; + float Sigma; + int N; + int option; + char DR[4]; + float DRscale; + }; +struct Model_Input +{ + char ModelName[10]; + int Begin; + int MaxT; + int nPar; + float *ptPET; + float *ptPrecip; + float *ptObserved; + float *ParRangeMin; + float *ParRangeMax; + float *IniStates; + }; + + +#endif diff --git a/src/ef5.rc b/src/ef5.rc new file mode 100644 index 0000000..fcdcd0c --- /dev/null +++ b/src/ef5.rc @@ -0,0 +1,26 @@ +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "Hydrometeorology and Remote Sensing Laboratory" + VALUE "FileDescription", "Ensemble Framework For Flash Flood Forecasting" + VALUE "FileVersion", "1.0" + VALUE "InternalName", "EF5" + VALUE "LegalCopyright", "Public Domain" + VALUE "OriginalFilename", "EF5.exe" + VALUE "ProductName", "EF5" + VALUE "ProductVersion", "1.0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END +id ICON "../ef5.ico" + diff --git a/src/misc_functions.cpp b/src/misc_functions.cpp new file mode 100755 index 0000000..e4f4408 --- /dev/null +++ b/src/misc_functions.cpp @@ -0,0 +1,404 @@ +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <math.h> +#include <time.h> +#include <sys/time.h> +#include "Messages.h" +#include "misc_functions.h" + +#ifdef WIN32 +#define UNIFORM_RAND (((float)rand()) / RAND_MAX) +#else +#define UNIFORM_RAND (drand48()) +#endif + +static void siftDown(float **numbers, int sort_col, int nc, int root, int bottom); + +void allocate2D(float ***array, int nrows, int ncols) +{ + //Function to dynamically allocate 2-dimensional array using malloc. + //Source: http://www.dreamincode.net/code/snippet1328.htm + /* allocate array of pointers */ + int i; + *array = (float**)malloc(nrows*sizeof(float *)); + float **vals = *array; + if (*array == NULL) + { + printf("ERROR in misc_functions.c/allocate2D at line 13: No Memory\n"); + exit(1); + } + /* allocate each row */ + for(i = 0; i < nrows; i++) + { + (*array)[i] = (float*)malloc( ncols*sizeof(float)); + if ((*array)[i] == NULL) + { + printf("ERROR in misc_functions.c/allocate2D at line 23: No Memory for array %d\n", i); + exit(1); + } + } + //INFO_LOGF("Allocated %p to %i", *array, nrows); + for (i = 0; i < nrows; i++) { + for (int j = 0; j < ncols; j++) { + vals[i][j] = 0.0; + } + } + } + +void deallocate2D(float ***array, int nrows) +{ + //Corresponding function to dynamically deallocate 2-dimensional array using + //malloc. Source: http://www.dreamincode.net/code/snippet1328.htm + /* deallocate each row */ + //INFO_LOGF("Deallocating %p to %i", *array, nrows); + int i; + for(i = 0; i < nrows; i++) + { + free((*array)[i]); + } + /* deallocate array of pointers */ + free(*array); + *array = NULL; + } + +void randperm(int **array, int n) +{ + int i, j, rnum, key = 1; + float nf = (float)(n); + for (i=0;i < n;i++) + { + rnum = rintf(UNIFORM_RAND * nf); + if (i == 0) + { + while (rnum == 0) + { + rnum = ceilf(UNIFORM_RAND * nf); + } + } + else + { + key = 1; + } + while (key > 0) + { + key = 0; + for (j=0;j < i; j++) + { + if (rnum == (*array)[j] || rnum == 0) + { + key = key + 1; + rnum = ceilf(UNIFORM_RAND * nf); + } + } + } + (*array)[i] = rnum; + } + } + +void nrandn(float **pArray, int nrows, int ncols) +{ + //Based on algorithm by Dr. Everett (Skip) Carter, Jr. + //from http://www.taygeta.com/random/gaussian.html + + int i,j; + float x1, x2, w, y1; + for (i=0;i < nrows;i++) + { + for (j=0;j < ncols;j++) + { + do + { + x1 = 2.0 * UNIFORM_RAND - 1.0; + x2 = 2.0 * UNIFORM_RAND - 1.0; + w = x1 * x1 + x2 * x2; + } while ( w >= 1.0 ); + w = sqrt( (-2.0 * log( w ) ) / w ); + y1 = x1 * w; + pArray[i][j] = y1; + } + } +} + +float sumarray(float *array, int nrows, int ncols) +{ + int i, idx, cont; + float suma; + suma = 0; + cont = 0; + if (nrows < 0 || ncols < 0) + { + printf("ERROR: sumarray: number of columns and/or number of rows must be positive integer. nrows = %d, ncols = %d\n", nrows, ncols); + exit(1); + } + if (nrows == 1 || ncols == 1) + { + //1D array + if (nrows > ncols) + { + //Column Vector + idx = nrows; + } + else if (ncols > nrows) + { + //Row Vector + idx = ncols; + } + else + { + //Single value, i.e. nrows = ncols = 1 + idx = nrows; + } + for (i = 0;i < idx;i++) + { + suma = suma + array[i]; + } + } + else + { + //2D array + for (i = 0;i < nrows*ncols;i++) + { + //for (j = 0;j < ncols;j++) + //{ + suma = suma + (array[i] + cont); + // cont = cont + 1; + //} + //cont = cont + 1; + } + } + return(suma); + } + +void reshape(float **oldarray, int m0, int n0, float ***newarray, int m, int n) +{ + int i, j; + int row,col; + row = 0; + col = 0; + if ((m0*n0) == (m*n)) + { + allocate2D(newarray, m, n); + + for (j=0;j < n;j++) + { + for (i=0;i < m;i++) + { + (*newarray)[i][j] = oldarray[row][col]; + row++; + if (row == m0) + { + row = 0; + col++; + } + } + } + } + else + { + printf("ERROR at reshape: m0*n0 must be equal to m*n\n"); + exit(1); + } + } + +float meanvar(float *arr, int no, MVOPS option) +{ + int i; + float var, max = arr[0], min = arr[0]; + float sum = 0.0, sum2 = 0.0, tavg; + float numArray = (float)no; + switch (option) { + case MVOP_MEAN: + for (i = 0; i < no; i++) { + sum += arr[i]; + } + return sum / numArray; + case MVOP_VAR: + case MVOP_STD: + for (i = 0; i < no; i++) { + sum += arr[i]; + } + tavg = sum / numArray; + + for (i = 0; i < no; i++) { + sum2 += pow(arr[i] - tavg, 2.0); + } + var = sum2 / (numArray - 1); + return ((option == MVOP_VAR) ? var : sqrt(var)); + case MVOP_MAX: + for (i = 0; i < no; i++) { + if (arr[i] > max) { + max = arr[i]; + } + } + return max; + case MVOP_MIN: + for (i = 0; i < no; i++) { + if (arr[i] < min) { + min = arr[i]; + } + } + return min; + default: + return 0; //should never get here + } + } + +void transp(float **oldarray, int m0, int n0, float ***newarray, bool preallocated) +{ + int i,j; + if (!preallocated) { + allocate2D(newarray, n0, m0); + } + if (newarray == NULL) + { + printf("ERROR at misc_functions.c at transp: Allocation not successfull\n"); + exit(1); + } + for (i=0;i < m0;i++) + { + for (j=0;j < n0;j++) + { + (*newarray)[j][i] = oldarray[i][j]; + } + } + } + +void sortarray(float *array, int n, const char *option) +{ + float temp; + int key = 1; + int i, j; + + //ASCENDING SORTING + if (strcmp(option, "asc") == 0) + { + while (key > 0) + { + key = 0; + for (i=0;i < n;i++) + { + for (j=i+1;j < n;j++) + { + if (array[i] > array[j]) + { + temp = array[j]; + array[j] = array[i]; + array[i] = temp; + key = key + 1; + break; + } + } + } + } + } + + //DESCENDING SORTING + if (strcmp(option, "des") == 0) + { + while (key > 0) + { + key = 0; + for (i=0;i < n;i++) + { + for (j=i+1;j < n;j++) + { + if (array[i] < array[j]) + { + temp = array[j]; + array[j] = array[i]; + array[i] = temp; + key = key + 1; + break; + } + } + } + } + } + + } + +float percentile(float *array, int nelem, float pctile) +{ + //Method to calculate percentiles, alternative by NIST. Source: Wikipedia. + float n, d, vp, v[nelem]; + int i, k; + + n = ((float)(nelem)/100) * pctile + 0.5; + k = (int)(n); + d = n - k; + for (i=0;i < nelem;i++) + { + v[i] = array[i]; + } + sortarray(&v[0], nelem, "asc"); + if (k == 0) + { + vp = v[0]; + } + else if (k == nelem) + { + vp = v[nelem-1]; + } + else + { + vp = v[k] + d*(v[k+1] - v[k]); + } + return(vp); + } + +void sortrows(float **array1, int nr, int nc, int sort_col, float **array2) +{ + int i, j, ii; + float temp; + + for(i=0;i < nr;i++) + { + for(j=0;j < nc;j++) + { + array2[i][j] = array1[i][j]; + } + } + +for (i = (nr / 2); i >= 0; i--) { + siftDown(array2, sort_col, nc, i, nr - 1); +} + + for (i = nr-1; i >= 1; i--) + { + for (ii=0; ii < nc; ii++) { + temp = array2[0][ii]; + array2[0][ii] = array2[i][ii]; + array2[i][ii] = temp; + } + siftDown(array2, sort_col, nc, 0, i-1); + } +} + +void siftDown(float **numbers, int sort_col, int nc, int root, int bottom) { + int done, maxChild, ii; + float temp; + + done = 0; + while ((root*2 <= bottom) && (!done)) + { + if (root*2 == bottom) + maxChild = root * 2; + else if (numbers[root * 2][sort_col] > numbers[root * 2 + 1][sort_col]) + maxChild = root * 2; + else + maxChild = root * 2 + 1; + + if (numbers[root][sort_col] < numbers[maxChild][sort_col]) + { + for (ii=0; ii < nc; ii++) { + temp = numbers[root][ii]; + numbers[root][ii] = numbers[maxChild][ii]; + numbers[maxChild][ii] = temp; + } + root = maxChild; + } + else + done = 1; + } +} diff --git a/src/misc_functions.h b/src/misc_functions.h new file mode 100755 index 0000000..fb2a182 --- /dev/null +++ b/src/misc_functions.h @@ -0,0 +1,23 @@ +#ifndef MISC_FUNCTIONS_H +#define MISC_FUNCTIONS_H + +enum MVOPS { + MVOP_MEAN, + MVOP_VAR, + MVOP_STD, + MVOP_MAX, + MVOP_MIN +}; + +void allocate2D(float*** array, int nrows, int ncols); +void deallocate2D(float*** array, int nrows); +void nrandn(float **pArray, int nrows, int ncols); +float sumarray(float *array, int nrows, int ncols); +void randperm(int **array, int n); +void reshape(float **oldarray, int m0, int n0, float ***newarray, int m, int n); +float meanvar(float *arr, int no, MVOPS option); +void transp(float **oldarray, int m0, int n0, float ***newarray, bool preallocated=false); +float percentile(float *array, int nelem, float pctile); +void sortarray(float *array, int n, const char *option); +void sortrows(float **array1, int nr, int nc, int sort_col, float **array2); +#endif diff --git a/test.txt b/test.txt deleted file mode 100644 index e69de29..0000000