├── .gitignore ├── LICENCE.md ├── README.md ├── compile_fmcd.sh ├── mcd.py ├── mcdcomp.py ├── netcdf ├── gfortran_netcdf4_fPIC └── gfortran_netcdf4_fpic_old ├── patch.txt ├── perso ├── ddcriterion.py ├── dunes │ ├── add_text.txt │ ├── dune.py │ ├── dune_lat_long.txt │ ├── histodune.py │ ├── plotdune.py │ ├── seasonal.py │ ├── time_dune.txt │ ├── u.txt │ ├── v.txt │ └── wheredune.py ├── dustdevil.py ├── gw.py ├── inimeso │ ├── from_gcm.py │ ├── inimeso.py │ ├── inimeso5.py │ ├── input_coord │ ├── profile.py │ ├── shift_temp.py │ └── venus │ │ ├── getvenus.py │ │ └── input_coord └── phoenix.py ├── quicktest.py ├── test_mcd ├── MCD_DATA ├── README ├── test_mcd.def ├── test_mcd.py └── test_mcd_light.py └── tutorial └── mcd-python_tutorial.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.log 3 | *.pyf 4 | *.pyc 5 | *.so 6 | input_more 7 | input_sounding 8 | input_therm 9 | input_dust 10 | input_water 11 | dustopacity.def 12 | perso/inimeso/*.png 13 | tutorial/*.png 14 | *.ipynb_checkpoints* 15 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **MCD-PYTHON: python-based interface to the Mars Climate Database** 2 | 3 | Open source code and contact information [available on github](https://github.com/aymeric-spiga) [no registration needed] 4 | 5 | * To get sources through git 6 | ~~~ 7 | git clone https://github.com/aymeric-spiga/mcd-python 8 | ~~~ 9 | 10 | * To get sources through SVN 11 | ~~~ 12 | svn co https://github.com/aymeric-spiga/mcd-python/trunk mcd-python 13 | ~~~ 14 | 15 | * To get a static ZIP file of the current version of the code, 16 | [click here](https://github.com/aymeric-spiga/mcd-python/archive/master.zip) 17 | 18 | ---- 19 | 20 | **How to install?** 21 | 22 | It is assumed you were able to compile successfully the `mcd` sources with `gfortran`. 23 | 24 | The `netCDF` library should be installed on your system. 25 | Moreover, from our experience, it seems that it must have been build 26 | using the `-fPIC` (for `gfortran`; the name of the option changes with compilers) 27 | option which generates position independent code suitable for use in a shared library. 28 | An example script is given in the `netcdf` folder. 29 | 30 | The installation below relies on `f2py` utility, which is part of the `numpy` package. 31 | 32 | 1. Getting the environment variables right: add the `mcd-python` folder to `PYTHONPATH` in your environment file (e.g. `.bashrc`) 33 | 34 | export PYTHONPATH=$PYTHONPATH:adapt_to_your_own/mcd-python 35 | 36 | 2. Modify the compile script `compile_fmcd.sh` to link your local `netCDF` libraries and `mcd` distribution (Fortran sources) 37 | 38 | 3. Check that `f2py` is included in your `python` library suite. 39 | 40 | 4. Run `compile_fmcd.sh` and check for the created `.so` file (its size should be about 1 Mo) 41 | 42 | ---- 43 | 44 | **Quick test** 45 | 46 | ~~~ 47 | quicktest.py 48 | ~~~ 49 | 50 | Next step is to try and learn about the use of `mcd` Python library with the `tutorial` folder. 51 | 52 | A more advanced example (direct use of `fmcd` compiled with `f2py`) is provided in the `test_mcd` folder. 53 | 54 | ---- 55 | 56 | **Python 3** 57 | 58 | *Solution suggested by Aaron Berliner* 59 | 60 | This can be done using the 2to3 package and the reindent 61 | 62 | Run 2to3 -v -n -W -f all mcd.py 63 | Run 2to3 -v -n -W -f all mcdcomp.py 64 | Run reindent mcd.py 65 | Run reindent mcdcomp.py 66 | 67 | Then upgrade to the appropriate basemap in python3. 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /compile_fmcd.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | ###################################################################################### 4 | ### 5 | ### compile_gfortran.sh 6 | ### 7 | ### - requirements: f2py tool + netCDF librairies compiled in Fortran 8 | ### 9 | ### ---> This should be used to make MCD fortran stuff directly accessible in python 10 | ### ---> This script is for gfortran, but it is easy to adapt to your other compilers 11 | ### ---> A file fmcd.so should be created 12 | ### ---> See mcd.py for use in python. Very easy! 13 | ### 14 | ### AS. 17/04/2012. 15 | ### TP/ AB : 13/10/2022 : update for MCD6.1 16 | ###################################################################################### 17 | 18 | 19 | NETCDF=/home/marshttp/NETCDF/netcdf64-4.0.1_gfortran_fPIC/ 20 | wheremcd="/home/marshttp/MCD_6.1/" 21 | 22 | 23 | version="6.1" 24 | 25 | ###################################################################################### 26 | ###################################################################################### 27 | ###################################################################################### 28 | 29 | ### LOG FILE 30 | num="" 31 | touch fmcd$num.log 32 | \rm fmcd$num.log 33 | 34 | ### COPY/PREPARE SOURCES 35 | ### perform changes that makes f2py not to fail 36 | sed s/"\!\!'"/"'"/g $wheremcd/mcd/MCD.F90 | sed s/"\!'"/"'"/g | sed -e 's/!/\'$'\n!/g' > tmp.MCD.F90 37 | 38 | 39 | ### BUILD THROUGH f2py WHAT IS NECESSARY TO CREATE THE PYTHON FUNCTIONS 40 | touch fmcd$num.pyf 41 | \rm fmcd$num.pyf 42 | echo -e " First f2py call : \n " > fmcd$num.log 43 | f2py -h fmcd$num.pyf -m fmcd$num tmp.MCD.F90 >> fmcd$num.log 2>&1 44 | 45 | ### IMPORTANT: we teach f2py about variables in the call_mcd subroutines which are intended to be out 46 | sed s/"real :: pres"/"real, intent(out) :: pres"/g fmcd$num.pyf | \ 47 | sed s/"real :: dens"/"real, intent(out) :: dens"/g | \ 48 | sed s/"real :: temp"/"real, intent(out) :: temp"/g | \ 49 | sed s/"real :: zonwind"/"real, intent(out) :: zonwind"/g | \ 50 | sed s/"real :: merwind"/"real, intent(out) :: merwind"/g | \ 51 | sed s/"real dimension(5) :: meanvar"/"real dimension(5),intent(out) :: meanvar"/g | \ 52 | sed s/"real dimension(100) :: extvar"/"real dimension(100),intent(out) :: extvar"/g | \ 53 | sed s/"real :: seedout"/"real, intent(out) :: seedout"/g | \ 54 | sed s/"integer :: ier"/"integer, intent(out) :: ier"/g > fmcd$num.pyf.modif 55 | mv fmcd$num.pyf.modif fmcd$num.pyf 56 | 57 | ### CUSTOMIZE fmcd.pyf TO ADD BUILT-IN INFO ABOUT VERSION and DATA LINKS 58 | datalink=`cd $wheremcd; pwd`"/data/" 59 | echo " usercode '''" > patchtmp.txt 60 | echo ' char dataloc[] = "'$datalink'";' >> patchtmp.txt 61 | echo ' char dataver[] = "'$version'";' >> patchtmp.txt 62 | echo " '''" >> patchtmp.txt 63 | sed '/python module fmcd ! in/r patchtmp.txt' fmcd$num.pyf > tmp ; mv tmp fmcd$num.pyf 64 | sed '/interface ! in :fmcd/r patch.txt' fmcd$num.pyf > tmp ; mv tmp fmcd$num.pyf 65 | 66 | ### BUILD 67 | echo -e " \n Second f2py call : \n " >> fmcd$num.log 68 | f2py -c fmcd$num.pyf tmp.MCD.F90 --fcompiler=gnu95 \ 69 | -L$NETCDF/lib -lnetcdf -lnetcdff\ 70 | -lm -I$NETCDF/include \ 71 | --f90flags="-fPIC -ffree-form -ffree-line-length-none" \ 72 | --f77flags="-fPIC" \ 73 | --verbose \ 74 | >> fmcd$num.log 2>&1 75 | 76 | #### CLEAN THE PLACE 77 | \rm tmp.MCD.F90 78 | \rm patchtmp.txt 79 | -------------------------------------------------------------------------------- /mcd.py: -------------------------------------------------------------------------------- 1 | #################################################### 2 | ### A Python Class for the Mars Climate Database ### 3 | ### ---------------------------------------------### 4 | ### Aymeric SPIGA 17-21/04/2012 ### 5 | ### ---------------------------------------------### 6 | ### (see mcdtest.py for examples of use) ### 7 | #################################################### 8 | 9 | ### 10 | from fmcd import mcd # MCD compiled with f2py 11 | from fmcd import dataloc # location of MCD data file 12 | from fmcd import dataver # compiled version of MCD 13 | ### 14 | import numpy as np 15 | import matplotlib.pyplot as mpl 16 | ### 17 | 18 | ## default number of points for each dimension 19 | dfzon = 64 #37 # zonal dimension 20 | dfmer = 48 #19 # meridional dimension 21 | dfver = 35 #20 # vertical dimension 22 | dflct = 25 #13 # local time dimension 23 | dfsea = 25 # solar long dimension 24 | ## default names 25 | lslab = "Areocentric longitude (degrees)" 26 | latlab = "North latitude (degrees)" 27 | lonlab = "East longitude (degrees)" 28 | ltlab = "Local time (Martian hour)" 29 | #NB: vertical labels are treated by .vertlabel() 30 | 31 | def errormess(text,printvar=None): 32 | print text 33 | if printvar is not None: print printvar 34 | exit() 35 | return 36 | 37 | class mcd_class(): 38 | 39 | def __repr__(self): 40 | # print out a help string when help is invoked on the object 41 | whatprint = 'MCD object. \"help(mcd)\" for more information\n' 42 | return whatprint 43 | 44 | ######################## 45 | ### Default settings ### 46 | ######################## 47 | 48 | def __init__(self): 49 | # default settings 50 | ## 0. general stuff 51 | self.name = "MCD_v"+dataver # this is coming from fmcd 52 | self.dset = dataloc # this is coming from fmcd 53 | self.ack = "Mars Climate Database (c) LMD/OU/IAA/ESA/CNES" 54 | ## 1. spatio-temporal coordinates 55 | self.lat = 0. 56 | self.lats = None 57 | self.late = None 58 | self.lon = 0. 59 | self.lons = None 60 | self.lone = None 61 | self.loct = 0. 62 | self.locts = None 63 | self.locte = None 64 | self.xdate = 0. # see datekey 65 | self.xdates = None 66 | self.xdatee = None 67 | self.xz = 10. # see zkey 68 | self.xzs = None 69 | self.xze = None 70 | ## 1bis. related settings 71 | self.zkey = 3 # specify that xz is the altitude above surface (m) 72 | # zkey : type of vertical coordinate xz 73 | # 1 = radius from centre of planet (m) 74 | # 2 = height above areoid (m) (MOLA zero datum) 75 | # 3 = height above surface (m) 76 | # 4 = pressure level (Pa) 77 | # 5 = altitude above mean Mars Radius(=3396000m) (m) 78 | self.datekey = 1 # 0 = "Earth time": xdate is given in Julian days (localtime must be set to zero) 79 | # 1 = "Mars date": xdate is the value of Ls 80 | 81 | ## 2. climatological options 82 | 83 | self.dust = 1 # climatological average scenario 84 | self.hrkey = 1 #set high resolution mode on (hrkey=0 to set high resolution off) 85 | 86 | ## 3. additional settings for advanced use 87 | 88 | self.extvarkey = np.ones(100) # now a table since MCD version 5 89 | self.perturkey = 0 #integer perturkey ! perturbation type (0: none) 90 | self.seedin = 1 #random number generator seed (unused if perturkey=0) 91 | self.gwlength = 0. #gravity Wave wavelength (unused if perturkey=0) 92 | ## outputs. just to define attributes. 93 | ## --> in update 94 | self.pres = None ; self.dens = None ; self.temp = None ; self.zonwind = None ; self.merwind = None ; self.meanvar = None ; self.extvar = None 95 | self.seedout = None ; self.ierr = None 96 | ## --> in prepare 97 | self.xcoord = None ; self.ycoord = None 98 | self.prestab = None ; self.denstab = None ; self.temptab = None 99 | self.zonwindtab = None ; self.merwindtab = None ; self.meanvartab = None ; self.extvartab = None 100 | ## plot stuff 101 | self.typex = None ; self.typey = None 102 | self.xlabel = None ; self.ylabel = None ; self.title = "" 103 | self.vertplot = False 104 | self.fmt = "%.1e" 105 | self.colorm = "jet" 106 | self.fixedlt = False 107 | self.averaging = None 108 | self.min2d = None 109 | self.max2d = None 110 | self.dpi = 80. 111 | self.islog = False 112 | self.proj = None 113 | self.trans = 0.0 114 | self.iscontour = False 115 | self.plat = 0.0 116 | self.plon = 0.0 117 | self.palt = None 118 | self.latpoint = None 119 | self.lonpoint = None 120 | 121 | def viking1(self): self.name = "Viking 1 site. MCD v4.3 output" ; self.lat = 22.48 ; self.lon = -49.97 ; self.xdate = 97. 122 | def viking2(self): self.name = "Viking 2 site. MCD v4.3 output" ; self.lat = 47.97 ; self.lon = -225.74 ; self.xdate = 117.6 123 | 124 | def getdustlabel(self): 125 | if self.dust == 1: 126 | self.dustlabel = "climatology average solar scenario" 127 | elif self.dust == 2: 128 | self.dustlabel = "climatology minimum solar scenario" 129 | elif self.dust == 3: 130 | self.dustlabel = "climatology maximum solar scenario" 131 | elif self.dust == 4: self.dustlabel = "dust storm minimum solar scenario" 132 | elif self.dust == 5: self.dustlabel = "dust storm average solar scenario" 133 | elif self.dust == 6: self.dustlabel = "dust storm maximum solar scenario" 134 | elif self.dust == 7: self.dustlabel = "warm scenario (dusty, maximum solar)" 135 | elif self.dust == 8: self.dustlabel = "cold scenario (low dust, minimum solar)" 136 | elif self.dust > 20: self.dustlabel = "Martian Year "+str(self.dust)+" scenario" 137 | 138 | def gettitle(self,oneline=False): 139 | self.getdustlabel() 140 | self.title = self.name + " with " + self.dustlabel + "." 141 | if self.datekey == 1: 142 | if self.xdates is None: 143 | self.title = self.title + " Ls " + str(self.xdate) + "deg." 144 | elif self.datekey == 0: 145 | self.title = self.title + " JD " + str(self.xdate) + "." 146 | if not oneline: self.title = self.title + "\n" 147 | if self.lats is None: 148 | self.title = self.title + " Latitude " + str(self.lat) + "N." 149 | if self.averaging == "lon": 150 | self.title = self.title + " Zonal mean over all longitudes." 151 | elif self.lons is None: 152 | self.title = self.title + " Longitude " + str(self.lon) + "E." 153 | if self.xzs is None: 154 | self.vertunits() 155 | self.title = self.title + " Altitude " + str(self.xz) + " " + self.vunits + "." 156 | if self.datekey == 1: 157 | if self.averaging == "loct": 158 | self.title = self.title + " Diurnal mean over all local times." 159 | else: 160 | if self.locts is None and self.averaging != "lon": 161 | self.title = self.title + " Local time " + str(self.loct) + "h" 162 | if self.lons is not None: # if longitude is a free dimension 163 | if not self.fixedlt: self.title = self.title + " (at longitude 0) " 164 | else: self.title = self.title + " (fixed at all longitudes) " 165 | if self.proj == "nsper" : 166 | if self.palt == 99999999. : 167 | self.title = self.title + "[view from lon "+str(self.plon)+"$\degree$E. lat "+str(self.plat)+"$\degree$N. infinite altitude]" 168 | else : 169 | self.title = self.title + "[view from lon "+str(self.plon)+"$\degree$E. lat "+str(self.plat)+"$\degree$N. alt "+str(self.palt)+ " km]" 170 | 171 | def getextvarlab(self,num): 172 | # MCD version 6.1 variables 173 | whichfield = { \ 174 | 91: "Pressure (Pa)", \ 175 | 92: "Density (kg/m3)", \ 176 | 93: "Temperature (K)", \ 177 | 94: "W-E wind component (m/s)", \ 178 | 95: "S-N wind component (m/s)", \ 179 | 96: "Horizontal wind speed (m/s)", \ 180 | 1: "Radial distance from planet center (m)", \ 181 | 2: "Altitude above areoid (Mars geoid) (m)", \ 182 | 3: "Altitude above local surface (m)", \ 183 | 4: "orographic height (m) (surface altitude above areoid)", \ 184 | 5: "GCM orography (m)", \ 185 | 6: "Local slope inclination (deg) (HR mode only)", \ 186 | 7: "Local slope orientation (deg) (0 deg Northward) (HR mode only)", \ 187 | 8: "Sun-Mars distance (in Astronomical Unit AU)", \ 188 | 9: "Ls, solar longitude of Mars (deg)", \ 189 | 10: "LST:Local true solar time (hrs)", \ 190 | 11: "LMT:Local mean time (hrs) at sought longitude", \ 191 | 12: "Universal solar time (LST at lon=0) (hrs)", \ 192 | 13: "Solar zenith angle (deg)", \ 193 | 14: "Surface temperature (K)", \ 194 | 15: "Surface pressure (Pa)", \ 195 | 16: "GCM surface pressure (Pa)", \ 196 | 17: "Potential temperature (K) (reference pressure=610Pa)", \ 197 | 18: "Downward Vertical wind component (m/s)", \ 198 | 19: "Zonal slope wind component (m/s) (HR mode only)", \ 199 | 20: "Meridional slope wind component (m/s) (HR mode only)", \ 200 | 21: "Surface pressure RMS day to day variations (Pa)", \ 201 | 22: "Surface temperature RMS day to day variations (K)", \ 202 | 23: "Atmospheric pressure RMS day to day variations (Pa)", \ 203 | 24: "Density RMS day to day variations (kg/m^3)", \ 204 | 25: "Temperature RMS day to day variations (K)", \ 205 | 26: "Zonal wind RMS day to day variations (m/s)", \ 206 | 27: "Meridional wind RMS day to day variations (m/s)", \ 207 | 28: "Vertical wind RMS day to day variations (m/s)", \ 208 | 29: "Incident solar flux at top of the atmosphere (W/m2)", \ 209 | 30: "solar flux reflected to space (W/m2)", \ 210 | 31: "Incident solar flux on horizontal surface (W/m2)", \ 211 | 32: "Incident solar flux on local slope (W/m2) (HR mode only)", \ 212 | 33: "Reflected solar flux on horizontal surface (W/m2)", \ 213 | 34: "thermal IR flux to space (W/m2)", \ 214 | 35: "thermal IR flux on surface (W/m2)", \ 215 | 36: "GCM surface roughness length z0 (m)", \ 216 | 37: "GCM surface thermal inertia", \ 217 | 38: "GCM surface bare ground albedo", \ 218 | 39: "Monthly mean dust column visible optical depth above surface", \ 219 | 40: "Daily mean dust column visible optical depth above surface", \ 220 | 41: "Dust mass mixing ratio (kg/kg)", \ 221 | 42: "Dust effective radius (m)", \ 222 | 43: "Daily mean dust deposition rate on horizontal surface (kg m-2 s-1)", \ 223 | 44: "Monthly mean surface CO2 ice layer (kg/m2)", \ 224 | 45: "Monthly mean surface H2O layer (kg/m2) (non perennial frost)", \ 225 | 46: "GCM perennial surface water ice (0 or 1)", \ 226 | 47: "Water vapor column (kg/m2)", \ 227 | 48: "Water vapor vol. mixing ratio (mol/mol)", \ 228 | 49: "Water ice column (kg/m2)", \ 229 | 50: "Water ice mixing ratio (mol/mol)", \ 230 | 51: "Water ice effective radius (m)", \ 231 | 52: "Convective Planetary Boundary Layer (PBL) height (m)", \ 232 | 53: "Max. upward convective wind within the PBL (m/s)", \ 233 | 54: "Max. downward convective wind within the PBL (m/s)", \ 234 | 55: "Convective vertical wind variance at level z (m2/s2)", \ 235 | 56: "Convective eddy vertical heat flux at level z (m/s/K)", \ 236 | 57: "Surface wind stress (kg/m/s2)", \ 237 | 58: "Surface sensible heat flux (W/m2) (<0 when flux from surf to atm.)", \ 238 | 59: "Air heat capacity Cp (J kg-1 K-1)", \ 239 | 60: "gamma=Cp/Cv Ratio of specific heats", \ 240 | 61: "R:Molecular gas constant (J K-1 kg-1)", \ 241 | 62: "Air viscosity estimation (N s m-2)", \ 242 | 63: "Scale height H(p) (m)", \ 243 | 64: "[CO2] volume mixing ratio (mol/mol)", \ 244 | 65: "[N2] volume mixing ratio (mol/mol)", \ 245 | 66: "[Ar] volume mixing ratio (mol/mol)", \ 246 | 67: "[CO] volume mixing ratio (mol/mol)", \ 247 | 68: "[O] volume mixing ratio (mol/mol)", \ 248 | 69: "[O2] volume mixing ratio (mol/mol)", \ 249 | 70: "[O3] volume mixing ratio (mol/mol)", \ 250 | 71: "[H] volume mixing ratio (mol/mol)", \ 251 | 72: "[H2] volume mixing ratio (mol/mol)", \ 252 | 73: "[He] volume mixing ratio (mol/mol)", \ 253 | 74: "CO2 column (kg/m2)", \ 254 | 75: "N2 column (kg/m2)", \ 255 | 76: "Ar column (kg/m2)", \ 256 | 77: "CO column (kg/m2)", \ 257 | 78: "O column (kg/m2)", \ 258 | 79: "O2 column (kg/m2)", \ 259 | 80: "O3 column (kg/m2)", \ 260 | 81: "H column (kg/m2)", \ 261 | 82: "H2 column (kg/m2)", \ 262 | 83: "He column (kg/m2)", \ 263 | 84: "Electron number density (particules/cm3)", \ 264 | 85: "Total electonic content (TEC) (particules/m2)" 265 | } 266 | 267 | if num not in whichfield: errormess("Incorrect subscript in extvar.") 268 | dastuff = whichfield[num] 269 | expf = "%.1e" 270 | if "variations (K)" in dastuff: self.fmt="%.1f" 271 | elif "(K)" in dastuff: self.fmt="%.0f" 272 | elif "effective radius" in dastuff: self.fmt=expf 273 | elif "(Pa)" in dastuff: self.fmt=expf 274 | elif "(W/m2)" in dastuff: self.fmt="%.0f" 275 | elif "(m/s)" in dastuff: self.fmt="%.1f" 276 | elif "(mol/mol)" in dastuff: self.fmt=expf 277 | elif "(kg/m2)" in dastuff: self.fmt=expf 278 | elif "(m)" in dastuff: self.fmt="%.0f" 279 | else: self.fmt=expf 280 | return dastuff 281 | 282 | def convertlab(self,num): 283 | 284 | ## a conversion from text inquiries to extvar numbers. to be completed. 285 | 286 | 287 | if num == "p": num = 91 288 | elif num == "rho": num = 92 289 | elif num == "t": num = 93 290 | elif num == "u": num = 94 291 | elif num == "v": num = 95 292 | elif num == "wind": num = 96 293 | elif num == "zradius": num=1 294 | elif num == "zareoid" : num =2 295 | elif num == "zsurface" : num = 3 296 | elif num == "oroheight" : num = 4 297 | elif num == "oro_gcm" : num = 5 298 | elif num == "theta_s" : num = 6 299 | elif num == "psi_s" : num = 7 300 | elif num == "marsau" : num = 8 301 | elif num == "ls" : num = 9 302 | elif num == "loctime" : num = 10 303 | elif num == "lmeantime" : num = 11 304 | elif num == "utime" : num = 12 305 | elif num == "solzenang" : num = 13 306 | elif num == "tsurf" : num = 14 307 | elif num == "ps" : num = 15 308 | elif num == "ps_gcm" : num = 16 309 | elif num == "potential_temp" : num = 17 310 | elif num == "w_l" : num = 18 311 | elif num == "zonal_slope_wind" : num = 19 312 | elif num == "merid_slope_wind" : num = 20 313 | elif num == "rmsps" : num = 21 314 | elif num == "rmstsurf" : num = 22 315 | elif num == "altrmsp" : num = 23 316 | elif num == "rmsrho" : num = 24 317 | elif num == "rmst" : num = 25 318 | elif num == "rmsu" : num = 26 319 | elif num == "rmsv" : num = 27 320 | elif num == "rmsw" : num = 28 321 | elif num == "fluxtop_dn_sw" : num = 29 322 | elif num == "fluxtop_up_sw" : num = 30 323 | elif num == "fluxsurf_dn_sw" : num = 31 324 | elif num == "fluxsurf_dn_sw_hr" : num = 32 325 | elif num == "fluxsurf_up_sw" : num = 33 326 | elif num == "fluxtop_lw" : num = 34 327 | elif num == "fluxsurf_lw" : num = 35 328 | elif num == "z_0" : num = 36 329 | elif num == "thermal_inertia" : num = 37 330 | elif num == "ground_albedo" : num = 38 331 | elif num == "dod" : num = 39 332 | elif num == "tauref" : num = 40 333 | elif num == "dust_mmr" : num = 41 334 | elif num == "dust_reff" : num = 42 335 | elif num == "dust_dep" : num = 43 336 | elif num == "co2ice" : num = 44 337 | elif num == "surf_h2o_ice" : num = 45 338 | elif num == "water_cap" : num = 46 339 | elif num == "col_h2ovapor" : num = 47 340 | elif num == "vmr_h2o" : num = 48 341 | elif num == "col_h2oice" : num = 49 342 | elif num == "vmr_h2oice" : num = 50 343 | elif num == "h2oice_reff" : num = 51 344 | elif num == "zmax" : num = 52 345 | elif num == "wstar_up" : num = 53 346 | elif num == "wstar_dn" : num = 54 347 | elif num == "vvv" : num = 55 348 | elif num == "vhf" : num = 56 349 | elif num == "surfstress" : num = 57 350 | elif num == "sensib_flux" : num = 58 351 | elif num == "Cp" : num = 59 352 | elif num == "gamma" : num = 60 353 | elif num == "Rgas" : num = 61 354 | elif num == "viscosity" : num = 62 355 | elif num == "pscaleheight" : num = 63 356 | elif num == "vmr_co2" : num = 64 357 | elif num == "vmr_n2" : num = 65 358 | elif num == "vmr_ar" : num = 66 359 | elif num == "vmr_co" : num = 67 360 | elif num == "vmr_o" : num = 68 361 | elif num == "vmr_o2" : num = 69 362 | elif num == "vmr_o3" : num = 70 363 | elif num == "vmr_h" : num = 71 364 | elif num == "vmr_h2" : num = 72 365 | elif num == "vmr_he" : num = 73 366 | elif num == "col_co2" : num = 74 367 | elif num == "col_n2" : num = 75 368 | elif num == "col_ar" : num = 76 369 | elif num == "col_co" : num = 77 370 | elif num == "col_o" : num = 78 371 | elif num == "col_o2" : num = 79 372 | elif num == "col_o3" : num = 80 373 | elif num == "col_h" : num = 81 374 | elif num == "col_h2" : num = 82 375 | elif num == "col_he" : num = 83 376 | elif num == "vmr_elec" : num = 84 377 | elif num == "col_elec" : num = 85 378 | elif not isinstance(num, np.int): errormess("field reference not found.") 379 | return num 380 | 381 | 382 | ################### 383 | ### One request ### 384 | ################### 385 | 386 | def update(self): 387 | # retrieve fields from MCD (call_mcd). more info in fmcd.call_mcd.__doc__ 388 | ## sanity first 389 | self.loct = abs(self.loct)%24 390 | if self.locts is not None and self.locte is not None: 391 | self.locts = abs(self.locts)%24 392 | self.locte = abs(self.locte)%24 393 | if self.locts == self.locte: self.locte = self.locts + 24 394 | ## ensure that local time = 0 when using Earth dates 395 | if self.datekey == 0: self.loct = 0. 396 | ### now MCD request 397 | (self.pres, self.dens, self.temp, self.zonwind, self.merwind, \ 398 | self.meanvar, self.extvar, self.seedout, self.ierr) \ 399 | = \ 400 | mcd.call_mcd(self.zkey,self.xz,self.lon,self.lat,self.hrkey, \ 401 | self.datekey,self.xdate,self.loct,self.dset,self.dust, \ 402 | self.perturkey,self.seedin,self.gwlength,self.extvarkey ) 403 | ## we use the end of extvar (unused) to store meanvar. this is convenient for getextvar(lab) 404 | self.extvar[90] = self.pres ; self.extvar[91] = self.dens 405 | self.extvar[92] = self.temp ; self.extvar[93] = self.zonwind ; self.extvar[94] = self.merwind 406 | self.extvar[95] = np.sqrt(self.extvar[93]**2 + self.extvar[94]**2) # calculate wind modulus 407 | ## treat missing values 408 | if self.temp == -999: self.extvar[:] = np.NaN ; self.meanvar[:] = np.NaN 409 | 410 | def printset(self): 411 | # print main settings 412 | print "zkey",self.zkey,"xz",self.xz,"lon",self.lon,"lat",self.lat,"hrkey",self.hrkey, \ 413 | "xdate",self.xdate,"loct",self.loct,"dust",self.dust 414 | 415 | def getnameset(self): 416 | # set a name referring to settings [convenient for databases] 417 | strlat = str(self.lat)+str(self.lats)+str(self.late) 418 | strlon = str(self.lon)+str(self.lons)+str(self.lone) 419 | strxz = str(self.xz)+str(self.xzs)+str(self.xze) 420 | strloct = str(self.loct)+str(self.locts)+str(self.locte) 421 | strdate = str(self.datekey)+str(self.xdate)+str(self.xdates)+str(self.xdatee) 422 | name = str(self.zkey)+strxz+strlon+strlat+str(self.hrkey)+strdate+strloct+str(self.dust) 423 | return name 424 | 425 | def printcoord(self): 426 | # print requested space-time coordinates 427 | print "LAT",self.lat,"LON",self.lon,"LOCT",self.loct,"XDATE",self.xdate 428 | 429 | def printmeanvar(self): 430 | # print mean MCD variables 431 | print "Pressure = %5.3f pascals. " % (self.pres) 432 | print "Density = %5.3f kilograms per cubic meter. " % (self.dens) 433 | print "Temperature = %3.0f kelvins (%4.0f degrees celsius)." % (self.temp,self.temp-273.15) 434 | print "Zonal wind = %5.3f meters per second." % (self.zonwind) 435 | print "Meridional wind = %5.3f meters per second." % (self.merwind) 436 | print "Total horizontal wind = %5.3f meters per second." % ( np.sqrt(self.zonwind**2 + self.merwind**2) ) 437 | 438 | def printextvar(self,num): 439 | # print extra MCD variables 440 | num = self.convertlab(num) 441 | dastr = str(self.extvar[num-1]) 442 | if dastr == "nan": print "!!!! There is a problem, probably a value is requested below the surface !!!!" 443 | else: print self.getextvarlab(num) + " ..... " + dastr 444 | 445 | def printallextvar(self): 446 | # print all extra MCD variables 447 | limit=85 #mcd6 number of extravar 448 | for i in range(limit): self.printextvar(i+1) 449 | 450 | def htmlprinttabextvar(self,tabtodo): 451 | self.fixedlt = True ## local time is real local time 452 | self.gettitle() 453 | print "
" 454 | print self.title 455 | print "
" 456 | print "" 459 | print "
" 460 | print self.ack 461 | print "
" 462 | #print "SETTINGS
" 463 | #self.printcoord() 464 | #self.printset() 465 | 466 | def printmcd(self): 467 | # 1. call MCD 2. print settings 3. print mean vars 468 | self.update() 469 | self.printcoord() 470 | print "-------------------------------------------" 471 | self.printmeanvar() 472 | 473 | ######################## 474 | ### Several requests ### 475 | ######################## 476 | 477 | def prepare(self,ndx=None,ndy=None): 478 | ### --- prepare I/O arrays for 1d slices --- 479 | ### NB: use ininterv to define xcoord and ycoord, not done here 480 | if ndx is None: print "No dimension in prepare. Exit. Set at least ndx." ; exit() 481 | #else: self.xcoord = np.ones(ndx) 482 | if ndy is None: dashape = (ndx) ; dashapemean = (ndx,6) ; dashapeext = (ndx,101) #; self.ycoord = None 483 | else: dashape = (ndx,ndy) ; dashapemean = (ndx,ndy,6) ; dashapeext = (ndx,ndy,101) #; self.ycoord = np.ones(ndy) 484 | self.prestab = np.ones(dashape) ; self.denstab = np.ones(dashape) ; self.temptab = np.ones(dashape) 485 | self.zonwindtab = np.ones(dashape) ; self.merwindtab = np.ones(dashape) 486 | self.meanvartab = np.ones(dashapemean) ; self.extvartab = np.ones(dashapeext) 487 | 488 | def getextvar(self,num): 489 | ### get a given var in extvartab 490 | try: field=self.extvartab[:,:,num] 491 | except: field=self.extvartab[:,num] 492 | return field 493 | 494 | def definefield(self,choice): 495 | ### for analysis or plot purposes, set field and field label from user-defined choice 496 | choice = self.convertlab(choice) 497 | field = self.getextvar(choice); fieldlab = self.getextvarlab(choice) 498 | ## fix for possibly slightly negative tracers 499 | if "(mol/mol)" in fieldlab or "(kg/kg)" in fieldlab or "(kg/m2)" in fieldlab or "(W/m2)" in fieldlab: 500 | ind = np.where(field < 1.e-30) 501 | if ind != -1: field[ind] = 0.e0 #1.e-30 ## 0 does not work everywhere. 502 | return field,fieldlab 503 | 504 | def ininterv(self,dstart,dend,nd,start=None,end=None,yaxis=False,vertcoord=False): 505 | ### user-defined start and end are used to create xcoord (or ycoord) vector 506 | if start is not None and end is not None: first, second = self.correctbounds(start,end,vertcoord) 507 | else: first, second = self.correctbounds(dstart,dend,vertcoord) 508 | if self.zkey != 4 or not vertcoord: tabtab = np.linspace(first,second,nd) 509 | else: tabtab = np.logspace(first,second,nd) 510 | if not yaxis: self.xcoord = tabtab 511 | else: self.ycoord = tabtab 512 | 513 | def correctbounds(self,start,end,vertcoord): 514 | if self.zkey != 4 or not vertcoord: 515 | # regular altitudes 516 | if start > end: first = end ; second = start 517 | else: first = start ; second = end 518 | else: 519 | # pressure: reversed avis 520 | if start < end: first = np.log10(end) ; second = np.log10(start) 521 | else: first = np.log10(start) ; second = np.log10(end) 522 | return first, second 523 | 524 | def vertlabel(self): 525 | # if self.zkey == 1: self.xlabel = "radius from centre of planet (m)" 526 | # elif self.zkey == 2: self.xlabel = "height above areoid (m) (MOLA zero datum)" 527 | # elif self.zkey == 3: self.xlabel = "height above surface (m)" 528 | # elif self.zkey == 4: self.xlabel = "pressure level (Pa)" 529 | # elif self.zkey == 5: self.xlabel = "altitude above mean Mars Radius(=3396000m) (m)" 530 | if self.zkey == 1: self.xlabel = "radius from centre of planet (m)" 531 | elif self.zkey == 2: self.xlabel = "altitude above MOLA$_0$ (m)" 532 | elif self.zkey == 3: self.xlabel = "height above surface (m)" 533 | elif self.zkey == 4: self.xlabel = "pressure (Pa)" 534 | elif self.zkey == 5: self.xlabel = "altitude above mean Mars radius (m)" 535 | 536 | def vertunits(self): 537 | if self.zkey == 1: self.vunits = "m CP" 538 | elif self.zkey == 2: self.vunits = "m AMR" 539 | elif self.zkey == 3: self.vunits = "m ALS" 540 | elif self.zkey == 4: self.vunits = "Pa" 541 | elif self.zkey == 5: self.vunits = "m AMMRad" 542 | 543 | def vertaxis(self,number,yaxis=False): 544 | if self.zkey == 2: self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True) 545 | elif self.zkey == 3: self.ininterv(0.,120000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True) 546 | elif self.zkey == 5: self.ininterv(-5000.,100000.,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True) 547 | elif self.zkey == 4: self.ininterv(1000.,0.001,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True) 548 | elif self.zkey == 1: self.ininterv(3396000,3596000,number,start=self.xzs,end=self.xze,yaxis=yaxis,vertcoord=True) 549 | 550 | ################### 551 | ### 1D analysis ### 552 | ################### 553 | 554 | def put1d(self,i): 555 | ## fill in subscript i in output arrays 556 | ## (arrays must have been correctly defined through prepare) 557 | if self.prestab is None: errormess("arrays must be prepared first through self.prepare") 558 | self.prestab[i] = self.pres ; self.denstab[i] = self.dens ; self.temptab[i] = self.temp 559 | self.zonwindtab[i] = self.zonwind ; self.merwindtab[i] = self.merwind 560 | self.meanvartab[i,1:5] = self.meanvar[0:4] ## note: var numbering according to MCD manual is kept 561 | self.extvartab[i,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept 562 | 563 | def diurnal(self,nd=dflct): 564 | ### retrieve a local time slice 565 | self.fixedlt = True ## local time is real local time 566 | save = self.loct 567 | self.xlabel = ltlab 568 | self.prepare(ndx=nd) ; self.ininterv(0.,24.,nd,start=self.locts,end=self.locte) 569 | for i in range(nd): self.loct = self.xcoord[i] ; self.update() ; self.put1d(i) 570 | self.loct = save 571 | 572 | def zonal(self,nd=dfzon): 573 | ### retrieve a longitude slice 574 | save = self.lon 575 | save2 = self.loct 576 | self.xlabel = lonlab 577 | self.prepare(ndx=nd) ; self.ininterv(-180.,180.,nd,start=self.lons,end=self.lone) 578 | if not self.fixedlt: umst = self.loct 579 | for i in range(nd): 580 | self.lon = self.xcoord[i] 581 | if not self.fixedlt: self.loct = (umst + self.lon/15.) % 24 582 | self.update() ; self.put1d(i) 583 | self.lon = save 584 | self.loct = save2 585 | 586 | def meridional(self,nd=dfmer): 587 | ### retrieve a latitude slice 588 | self.fixedlt = True ## local time is real local time 589 | save = self.lat 590 | self.xlabel = latlab 591 | self.prepare(ndx=nd) ; self.ininterv(-90.,90.,nd,start=self.lats,end=self.late) 592 | for i in range(nd): self.lat = self.xcoord[i] ; self.update() ; self.put1d(i) 593 | self.lat = save 594 | 595 | def profile(self,nd=dfver,tabperso=None): 596 | ### retrieve an altitude slice (profile) 597 | self.fixedlt = True ## local time is real local time 598 | save = self.xz 599 | self.vertlabel() 600 | self.vertplot = True 601 | if tabperso is not None: nd = len(tabperso) 602 | correct = False 603 | self.prepare(ndx=nd) ; self.vertaxis(nd) 604 | if tabperso is not None: self.xcoord = tabperso 605 | for i in range(nd): self.xz = self.xcoord[i] ; self.update() ; self.put1d(i) 606 | self.xz = save 607 | 608 | def seasonal(self,nd=dfsea): 609 | ### retrieve a seasonal slice 610 | save = self.xdate 611 | self.xlabel = lslab 612 | self.prepare(ndx=nd) ; self.ininterv(0.,360.,nd,start=self.xdates,end=self.xdatee) 613 | for i in range(nd): self.xdate = self.xcoord[i] ; self.update() ; self.put1d(i) 614 | self.xdate = save 615 | 616 | def getascii(self,tabtodo,filename="output.txt",log=None): 617 | ### print out values in an ascii file 618 | import datetime 619 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 620 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 621 | asciifile = open(filename, "w") 622 | if log is not None: 623 | logfile = open(log, "a") 624 | for i in range(len(tabtodo)): 625 | txt = "##########################################################################################\n" 626 | ### print out header 627 | (field, fieldlab) = self.definefield(tabtodo[i]) 628 | self.gettitle(oneline=True) 629 | txt = txt + "### " + self.title + "\n" 630 | txt = txt.replace("scenario.","scenario.\n###") 631 | txt = txt + "### --------------------------------------------------------------------------------------\n" 632 | txt = txt + "### Column 1 is " + self.xlabel + "\n" 633 | dim = field.ndim 634 | if (dim == 1): 635 | txt = txt + "### Column 2 is " + fieldlab + "\n" 636 | data = txt 637 | elif (dim == 2): 638 | txt = txt + "### Columns 2+ are " + fieldlab + "\n" 639 | txt = txt + "### Line 1 is " + self.ylabel + "\n" 640 | txt = txt + "### --------------------------------------------------------------------------------------\n" 641 | txt = txt + "### Retrieved on: " + datetime.datetime.today().isoformat() + "\n" 642 | txt = txt + "### " + self.ack + "\n" 643 | txt = txt + "##########################################################################################\n" 644 | ### print out data 645 | data = txt 646 | if (dim == 1): 647 | for ix in range(len(self.xcoord)): 648 | data = data + "%15.5e%15.5e\n" % ( self.xcoord[ix], field[ix] ) 649 | elif (dim == 2): 650 | data = data + "---- ||" 651 | for iy in range(len(self.ycoord)): 652 | data = data + "%15.5e" % ( self.ycoord[iy] ) 653 | data = data + "\n-----------------------------------\n" 654 | for ix in range(len(self.xcoord)): 655 | zestr = "%+.03d ||" % (self.xcoord[ix]) 656 | for iy in range(len(self.ycoord)): 657 | zestr = zestr + "%15.5e" % (field[ix,iy]) 658 | data = data + zestr+"\n" 659 | asciifile.write(data) 660 | if log is not None: 661 | logfile.write(txt) 662 | asciifile.close() 663 | if log is not None: 664 | logfile.close() 665 | return 666 | 667 | def makeplot1d(self,choice): 668 | ### one 1D plot is created for the user-defined variable in choice. 669 | (field, fieldlab) = self.definefield(choice) 670 | if not self.vertplot: absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel 671 | else: ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel 672 | mpl.plot(absc,ordo,'-bo') ; mpl.ylabel(ordolab) ; mpl.xlabel(absclab) #; mpl.xticks(query.xcoord) 673 | # cases with log axis 674 | if self.zkey == 4: mpl.semilogy() ; ax = mpl.gca() ; ax.set_ylim(ax.get_ylim()[::-1]) 675 | if not self.vertplot and self.islog: mpl.semilogy() 676 | if self.vertplot and self.islog: mpl.semilogx() 677 | mpl.figtext(0.5, 0.01, self.ack, ha='center') 678 | 679 | def plot1d(self,tabtodo): 680 | ### complete 1D figure with possible multiplots 681 | import mcdcomp as mcdcomp 682 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 683 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 684 | fig = mpl.figure() ; subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig ) 685 | for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1).grid(True, linestyle=':', color='grey') ; self.makeplot1d(tabtodo[i]) 686 | mpl.show() 687 | 688 | def htmlplot1d(self,tabtodo,figname="temp.png",title=""): 689 | ### complete 1D figure with possible multiplots 690 | ### added in 09/2012 for online MCD 691 | ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html 692 | import mcdcomp as mcdcomp 693 | from matplotlib.figure import Figure 694 | from matplotlib.backends.backend_agg import FigureCanvasAgg 695 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 696 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 697 | 698 | howmanyplots = len(tabtodo) 699 | if howmanyplots == 1: fig = Figure(figsize=(16,8)) 700 | elif howmanyplots == 2: fig = Figure(figsize=(8,8)) 701 | elif howmanyplots == 3: fig = Figure(figsize=(8,16)) 702 | elif howmanyplots == 4: fig = Figure(figsize=(16,8)) 703 | 704 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig ) 705 | for i in range(len(tabtodo)): 706 | yeah = fig.add_subplot(subv,subh,i+1) #.grid(True, linestyle=':', color='grey') 707 | choice = tabtodo[i] 708 | (field, fieldlab) = self.definefield(choice) 709 | 710 | # in log plots we do not show the negative values 711 | if self.islog: field[np.where(field <= 0.e0)] = np.nan 712 | 713 | if not self.vertplot: absc = self.xcoord ; ordo = field ; ordolab = fieldlab ; absclab = self.xlabel 714 | else: ordo = self.xcoord ; absc = field ; absclab = fieldlab ; ordolab = self.xlabel 715 | 716 | yeah.plot(absc,ordo,'-bo') #; mpl.xticks(query.xcoord) 717 | ax = fig.gca() ; ax.set_ylabel(ordolab) ; ax.set_xlabel(absclab) 718 | 719 | if self.xzs is not None and self.zkey == 4: ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1]) 720 | if not self.vertplot and self.islog: ax.set_yscale('log') 721 | if self.vertplot and self.islog: ax.set_xscale('log') 722 | 723 | if self.lats is not None: ax.set_xticks(np.arange(-90,91,15)) ; ax.set_xbound(lower=self.lats, upper=self.late) 724 | elif self.lons is not None: ax.set_xticks(np.arange(-360,361,30)) ; ax.set_xbound(lower=self.lons, upper=self.lone) 725 | elif self.locts is not None: ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte) 726 | elif self.xdates is not None: ax.set_xticks(np.arange(0,361,30)) ; ax.set_xbound(lower=self.xdates, upper=self.xdatee) 727 | 728 | ## does not work 729 | #ax.ticklabel_format(useOffset=False,axis='x') 730 | #ax.ticklabel_format(useOffset=False,axis='y') 731 | 732 | ax.grid(True, linestyle=':', color='grey') 733 | 734 | self.gettitle() 735 | fig.text(0.5, 0.95, self.title, ha='center', transform=fig.gca().transAxes, fontweight='bold') 736 | fig.text(0.5, 0.01, self.ack, ha='center') 737 | canvas = FigureCanvasAgg(fig) 738 | # The size * the dpi gives the final image size 739 | # a4"x4" image * 80 dpi ==> 320x320 pixel image 740 | canvas.print_figure(figname, dpi=self.dpi) 741 | 742 | ################### 743 | ### 2D analysis ### 744 | ################### 745 | 746 | def definetype(self,typex=None,typey=None): 747 | ### get the type of 2D plot 748 | # -- we keep a "forcing" option for retrocompatibility (e.g. for maps) 749 | # -- this is meant to ultimately disappear 750 | if typex is not None and typey is not None: 751 | self.typex = typex 752 | self.typey = typey 753 | return 754 | # -- retrieve kind of time axis 755 | if self.locts is not None: 756 | zetypet = "loct" 757 | # case of a ls/lt map (all-time plot) 758 | if self.xdates is not None: 759 | self.typex = "ls" ; self.typey = zetypet 760 | return 761 | elif self.xdates is not None: 762 | zetypet = "ls" 763 | else: 764 | zetypet = None 765 | # -- retrieve kind of spatial axis 766 | if self.lons is not None: 767 | zetypes = "lon" 768 | # case of a lat/lon map 769 | if self.lats is not None: 770 | self.typex = zetypes ; self.typey = "lat" 771 | return 772 | elif self.lats is not None: 773 | zetypes = "lat" 774 | # -- explore all possibilities 775 | if zetypet is None: 776 | # this is horizontal/vertical section 777 | self.typex = zetypes ; self.typey = "alt" # secalt 778 | else: 779 | # there is a time axis 780 | # -- first we consider that spatial could be altitude 781 | # -- others (lat & lon) were done above 782 | if self.xzs is not None: 783 | zetypes = "alt" 784 | # -- second we organize coordinates as usual 785 | if zetypet == "loct": 786 | if zetypes == "alt": 787 | self.typex = zetypet ; self.typey = zetypes # hovmoller with alt 788 | else: 789 | self.typex = zetypes ; self.typey = zetypet # hovmoller 790 | elif zetypet == "ls": 791 | self.typex = zetypet ; self.typey = zetypes # seasonal 792 | return 793 | 794 | def query2d(self,typex=None,typey=None,ndmean=32): 795 | ### retrieve a 2D slice 796 | # save query 797 | save1 = self.lon ; save2 = self.xz ; save3 = self.loct ; save4 = self.lat ; save5 = self.xdate 798 | # initialize 799 | if not self.fixedlt: 800 | umst = self.loct # local time is not fixed. user-defined local time is at longitude 0. 801 | # define the type of 2D plot 802 | # -- hard setting of typex and typey is meant to disappear 803 | self.definetype(typex=typex,typey=typey) 804 | # settings for averaging 805 | if self.averaging is not None: 806 | coordmean = self.meandim(ndmean=ndmean) 807 | if self.averaging == "lon": 808 | self.fixedlt = False 809 | umst = self.loct # shouldn't it be zero? does not matter anyways... 810 | # get coordinates 811 | self.fillcoord() 812 | # MAIN QUERY LOOP 813 | for i in range(self.xcoord.size): 814 | for j in range(self.ycoord.size): 815 | # fill in correct values for query 816 | self.filldim(self.xcoord[i],self.ycoord[j]) 817 | # emulate "natural" global local time if not free dim and not fixedlt 818 | if self.locts is None: 819 | if not self.fixedlt: 820 | self.loct = (umst + self.lon/15.) % 24 821 | # get field (simple or average) 822 | if self.averaging is None: 823 | self.update() 824 | else: 825 | self.meanperform(coordmean,umst=umst) 826 | # fill in 2D array 827 | self.put2d(i,j) 828 | # reinstall init state 829 | if not self.fixedlt: self.loct = umst 830 | self.lon = save1 ; self.xz = save2 ; self.loct = save3 ; self.lat = save4 ; self.xdate = save5 831 | 832 | ################################################ 833 | ### retro-compatibility functions 834 | ### -- only latlon is used now in htmlmap2d query 835 | ### -- htmlplot2d uses now query2d() in which plot type is set 836 | ### -- but what is below could be useful in interactive mode 837 | def latlon(self,typex="lon",typey="lat"): 838 | ### retrieve a latitude/longitude slice 839 | self.query2d(typex=typex,typey=typey) 840 | def secalt(self,typex="lat"): 841 | ### retrieve a coordinate/altitude slice 842 | self.query2d(typex=typex,typey="alt") 843 | def hovmoller(self,typex="lat",typey="loct"): 844 | ### retrieve a time/other coordinate slice 845 | if typey == "ls": 846 | typey = typex ; typex = "ls" #usually in seasonal plots, Ls is in x-axis 847 | self.query2d(typex=typex,typey=typey) 848 | def zonalmean(self,ndmean=32,typey="alt",typex="lat"): 849 | ### retrieve a zonalmean lat/altitude or ls/lat slice 850 | self.averaging="lon" 851 | self.query2d(typex=typex,typey=typey) 852 | ################################################ 853 | 854 | def fillcoord(self): 855 | ### define coordinates. using global default values for number of points. 856 | ### prepare output arrays once coordinates are defined. 857 | # fill in coord properties // x-axis 858 | if self.typex == "lat": 859 | ndx = dfmer 860 | self.xlabel = latlab 861 | self.ininterv(-90.,90.,ndx,start=self.lats,end=self.late) ## do we want to change ndx or just use dfzon? 862 | elif self.typex == "lon": 863 | ndx = dfzon 864 | self.xlabel = lonlab 865 | self.ininterv(-180.,180.,ndx,start=self.lons,end=self.lone) 866 | elif self.typex == "alt": 867 | ndx = dfver 868 | self.vertlabel() 869 | self.vertaxis(dfver) 870 | elif self.typex == "ls": 871 | ndx = dfsea 872 | self.xlabel = lslab 873 | self.ininterv(0.,360.,ndx,start=self.xdates,end=self.xdatee) 874 | elif self.typex == "loct": 875 | ndx = dflct 876 | self.xlabel = ltlab 877 | self.ininterv(0.,24.,ndx,start=self.locts,end=self.locte) 878 | # fill in coord properties // y-axis 879 | if self.typey == "lat": 880 | ndy = dfmer 881 | self.ylabel = latlab 882 | self.ininterv(-90.,90.,ndy,start=self.lats,end=self.late,yaxis=True) 883 | elif self.typey == "lon": 884 | ndy = dfzon 885 | self.ylabel = lonlab 886 | self.ininterv(-180.,180.,ndy,start=self.lons,end=self.lone,yaxis=True) 887 | elif self.typey == "alt": 888 | ndy = dfver 889 | sav = self.xlabel # save because used below as intermediate (to be improved) 890 | self.vertlabel() ; self.ylabel = self.xlabel 891 | self.xlabel = sav 892 | self.vertaxis(ndy,yaxis=True) 893 | elif self.typey == "ls": 894 | ndy = dfsea 895 | self.ylabel = lslab 896 | self.ininterv(0.,360.,ndy,start=self.xdates,end=self.xdatee,yaxis=True) 897 | elif self.typey == "loct": 898 | ndy = dflct 899 | self.ylabel = ltlab 900 | self.ininterv(0.,24.,ndy,start=self.locts,end=self.locte,yaxis=True) 901 | # prepare arrays with correct dimensions 902 | self.prepare(ndx=ndx,ndy=ndy) 903 | 904 | def filldim(self,xx,yy): 905 | # fill in individual values in axis 906 | tab = [[self.typex,xx],[self.typey,yy]] 907 | for ttt in tab: 908 | if "lat" in ttt[0]: self.lat = ttt[1] 909 | if "lon" in ttt[0]: self.lon = ttt[1] 910 | if "alt" in ttt[0]: self.xz = ttt[1] 911 | if "loct" in ttt[0]: self.loct = ttt[1] 912 | if "ls" in ttt[0]: self.xdate = ttt[1] 913 | 914 | def meandim(self,ndmean=32): 915 | ### define averaging dimension 916 | sav = self.xcoord #using xcoord as an intermediate 917 | if self.averaging == "lon": 918 | self.ininterv(-180.,180.,ndmean) 919 | elif self.averaging == "loct": 920 | self.ininterv(0.,24.,ndmean) 921 | coordmean = self.xcoord 922 | self.xcoord = sav 923 | return coordmean 924 | 925 | def meanperform(self,coordmean,umst=None): 926 | ndmean = coordmean.size 927 | meanpres = 0. ; meandens = 0. ; meantemp = 0. ; meanzonwind = 0. ; meanmerwind = 0. ; meanmeanvar = np.zeros(5) ; meanextvar = np.zeros(100) 928 | for ccc in coordmean: 929 | if self.averaging == "lon": 930 | # zonal averaging with forcing of local time 931 | self.lon = ccc 932 | self.loct = (umst + self.lon/15.) % 24 #fixedlt false for this case 933 | elif self.averaging == "loct": 934 | self.loct = ccc 935 | self.update() 936 | meanpres = meanpres + self.pres/float(ndmean) ; meandens = meandens + self.dens/float(ndmean) ; meantemp = meantemp + self.temp/float(ndmean) 937 | meanzonwind = meanzonwind + self.zonwind/float(ndmean) ; meanmerwind = meanmerwind + self.merwind/float(ndmean) 938 | meanmeanvar = meanmeanvar + self.meanvar/float(ndmean) ; meanextvar = meanextvar + self.extvar/float(ndmean) 939 | self.pres=meanpres ; self.dens=meandens ; self.temp=meantemp ; self.zonwind=meanzonwind ; self.merwind=meanmerwind 940 | self.meanvar=meanmeanvar ; self.extvar=meanextvar 941 | 942 | def put2d(self,i,j): 943 | ## fill in subscript i,j in output arrays 944 | ## (arrays must have been correctly defined through prepare) 945 | if self.prestab is None: errormess("arrays must be prepared first through self.prepare") 946 | self.prestab[i,j] = self.pres ; self.denstab[i,j] = self.dens ; self.temptab[i,j] = self.temp 947 | self.zonwindtab[i,j] = self.zonwind ; self.merwindtab[i,j] = self.merwind 948 | self.meanvartab[i,j,1:5] = self.meanvar[0:4] ## note: var numbering according to MCD manual is kept 949 | self.extvartab[i,j,1:100] = self.extvar[0:99] ## note: var numbering according to MCD manual is kept 950 | 951 | def makemap2d(self,choice,incwind=False,proj="cyl"): 952 | ### one 2D map is created for the user-defined variable in choice. 953 | import mcdcomp as mcdcomp 954 | self.latlon() ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d) 955 | if choice == "wind" or incwind: 956 | (windx, fieldlabwx) = self.definefield("u") 957 | (windy, fieldlabwy) = self.definefield("v") 958 | if choice == "wind": 959 | field = np.sqrt(windx*windx + windy*windy) 960 | fieldlab = "Horizontal wind speed (m/s)" 961 | else: 962 | (field, fieldlab) = self.definefield(choice) 963 | if incwind: mcdcomp.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj,vecx=windx,vecy=windy,vmin=self.min2d,vmax=self.max2d) #,stride=1) 964 | else: mcdcomp.maplatlon(self.xcoord,self.ycoord,field,title=fieldlab,proj=proj,vmin=self.min2d,vmax=self.max2d) 965 | mpl.figtext(0.5, 0.0, self.ack, ha='center') 966 | 967 | def map2d(self,tabtodo,incwind=False,proj="cyl"): 968 | ### complete 2D figure with possible multiplots 969 | import mcdcomp as mcdcomp 970 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 971 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 972 | fig = mpl.figure() 973 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig ) 974 | for i in range(len(tabtodo)): mpl.subplot(subv,subh,i+1) ; self.makemap2d(tabtodo[i],incwind=incwind,proj=proj) 975 | mpl.show() 976 | 977 | def makeinterv(self): 978 | self.latinterv = 30. 979 | self.loninterv = 45. 980 | if self.lats is not None: 981 | if (abs(self.late-self.lats) < 90.): self.latinterv = 10. 982 | if (abs(self.late-self.lats) < 10.): self.latinterv = 1. 983 | if self.lons is not None: 984 | if (abs(self.lone-self.lons) < 135.): self.loninterv = 15. 985 | if (abs(self.lone-self.lons) < 15.): self.loninterv = 1. 986 | 987 | def htmlmap2d(self,tabtodo,incwind=False,figname="temp.png"): 988 | ### complete 2D figure with possible multiplots 989 | ### added in 09/2012 for online MCD 990 | ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html 991 | import mcdcomp as mcdcomp 992 | from matplotlib.figure import Figure 993 | from matplotlib.backends.backend_agg import FigureCanvasAgg 994 | from matplotlib.cm import get_cmap 995 | from matplotlib import rcParams 996 | import matplotlib.pyplot as plt 997 | #### 998 | isproj = (self.proj is not None) 999 | if isproj: 1000 | from mpl_toolkits.basemap import Basemap 1001 | #### 1002 | if (self.trans > 0.): isback = True 1003 | else: isback = False 1004 | if (self.trans > 0.99): self.iscontour = True 1005 | #### 1006 | 1007 | try: 1008 | from scipy.io import netcdf 1009 | filename = dataloc+"/mola32.nc" ; back = "alt" 1010 | zefile = netcdf.netcdf_file(filename, 'r') 1011 | fieldc = zefile.variables[back][::32,::32]/1000. 1012 | yc = zefile.variables['latitude'][::32] 1013 | xc = zefile.variables['longitude'][::32] 1014 | zefile.close() 1015 | havetopo = True 1016 | except: 1017 | print "Trouble with netCDF or surface.nc file. Continue without topo lines." 1018 | havetopo = False 1019 | 1020 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 1021 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 1022 | 1023 | fig = mcdcomp.setfig(len(tabtodo),proj=self.proj) 1024 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig ) 1025 | 1026 | for i in range(len(tabtodo)): 1027 | yeah = fig.add_subplot(subv,subh,i+1) 1028 | choice = tabtodo[i] 1029 | self.latlon() #ndx=64,ndy=48) 1030 | ## a map is implicitely a lat-lon plot. otherwise it is a plot (cf. makeplot2d) 1031 | (field, fieldlab) = self.definefield(choice) 1032 | if incwind: (windx, fieldlabwx) = self.definefield("u") ; (windy, fieldlabwy) = self.definefield("v") 1033 | 1034 | ndiv = 40 1035 | vecx=None ; vecy=None ; stride=2 1036 | lon = self.xcoord ; lat = self.ycoord 1037 | 1038 | if isproj: 1039 | ## 1040 | if self.plat is None: self.plat = 0.5*(self.lats+self.late) 1041 | if self.plon is None: self.plon = 0.5*(self.lons+self.lone) 1042 | if self.palt is None: self.palt = 99999999. 1043 | 1044 | ## 1045 | if self.proj == "cyl": yeah = Basemap(projection=self.proj,\ 1046 | llcrnrlat=self.lats,urcrnrlat=self.late,\ 1047 | llcrnrlon=self.lons,urcrnrlon=self.lone,\ 1048 | ax=yeah,resolution=None) 1049 | elif self.proj == "laea": yeah = Basemap(projection=self.proj,ax=yeah,resolution=None,\ 1050 | lon_0=self.plon,lat_0=self.plat,\ 1051 | llcrnrlat=self.lats,urcrnrlat=self.late,\ 1052 | llcrnrlon=self.lons,urcrnrlon=self.lone) 1053 | elif self.proj == "npstere": yeah = Basemap(projection=self.proj,boundinglat=self.plat,lon_0=self.plon,resolution=None,ax=yeah) 1054 | elif self.proj == "spstere": yeah = Basemap(projection=self.proj,boundinglat=self.plat,lon_0=self.plon,resolution=None,ax=yeah) 1055 | elif self.proj == "ortho": yeah = Basemap(projection=self.proj,lat_0=self.plat,lon_0=self.plon,resolution=None,ax=yeah) 1056 | elif self.proj == "robin": yeah = Basemap(projection=self.proj,lon_0=0.,resolution=None,ax=yeah) 1057 | elif self.proj == "nsper": yeah = Basemap(projection=self.proj,lat_0=self.plat,lon_0=self.plon,satellite_height=self.palt*1000.,resolution=None,ax=yeah) 1058 | 1059 | ## NB: resolution=None is here to avoid loading coastlines which caused problems with some (plat,plon) couples 1060 | ### background 1061 | if isback: 1062 | img="/home/marshttp/www-mars/mcd_python/MarsMap_2500x1250.jpg" 1063 | yeah.warpimage(img,scale=0.75) 1064 | mertab,partab = np.r_[-180.:180.:30.],np.r_[-90.:90.:15.] 1065 | merlab,parlab = [0,0,0,1],[1,0,0,0] 1066 | #format = '%.1f' 1067 | 1068 | if(self.proj=="nsper") : 1069 | yeah.drawmeridians(mertab,color="grey") 1070 | yeah.drawparallels(partab,color="grey") 1071 | else : 1072 | yeah.drawmeridians(mertab,color="grey",labels=merlab) 1073 | yeah.drawparallels(partab,color="grey",labels=parlab) 1074 | 1075 | [lon2d,lat2d] = np.meshgrid(lon,lat) 1076 | x, y = yeah(lon2d, lat2d) 1077 | else: 1078 | x = lon ; y = lat 1079 | 1080 | ## define field. bound field. 1081 | what_I_plot = np.transpose(field) 1082 | zevmin,zevmax,limtype = mcdcomp.setbounds(what_I_plot,vmin=self.min2d,vmax=self.max2d) 1083 | ## define contour field levels. define color palette 1084 | ticks = ndiv + 1 1085 | zelevels = np.linspace(zevmin,zevmax,ticks) 1086 | if zevmin==zevmax: # handle case where all values of the array are the same 1087 | zelevels = np.linspace(zevmin*0.9,zevmax*1.1,ticks) 1088 | palette = get_cmap(name=self.colorm) 1089 | 1090 | ## topography contours 1091 | if havetopo: 1092 | rcParams['contour.negative_linestyle'] = 'solid' # negative contours solid instead of dashed 1093 | zelevc = np.linspace(-9.,20.,11.,0.) 1094 | if isproj: 1095 | [xc2,yc2] = np.meshgrid(xc,yc) 1096 | xc3,yc3 = yeah(xc2,yc2) 1097 | yeah.contour( xc3, yc3, fieldc, zelevc, colors='black',linewidths = 0.4 ) 1098 | [xc2,yc2] = np.meshgrid(np.array(xc)-360.,yc) 1099 | xc3,yc3 = yeah(xc2,yc2) 1100 | yeah.contour( xc3, yc3, fieldc, zelevc, colors='black',linewidths = 0.4 ) 1101 | else: 1102 | yeah.contour( np.array(xc) , yc, fieldc, zelevc, colors='black',linewidths = 0.4) 1103 | yeah.contour( np.array(xc) - 360., yc, fieldc, zelevc, colors='black',linewidths = 0.4) 1104 | 1105 | # contour field 1106 | if self.iscontour: c = yeah.contour( x, y, what_I_plot, zelevels, cmap = palette ) 1107 | else: c = yeah.contourf( x, y, what_I_plot, zelevels, cmap = palette, alpha = 1.-self.trans, extend=limtype ) 1108 | 1109 | # colorbar 1110 | if not isproj: orientation='vertical' ; frac = 0.15 ; pad = 0.04 ; lu = 0.5 1111 | elif self.proj in ['moll']: orientation="horizontal" ; frac = 0.08 ; pad = 0.03 ; lu = 1.0 1112 | elif self.proj in ['robin']: orientation="horizontal" ; frac = 0.07 ; pad = 0.1 ; lu = 1.0 1113 | elif self.proj in ['cyl']: orientation="vertical" ; frac = 0.023 ; pad = 0.03 ; lu = 0.5 1114 | else: orientation='vertical' ; frac = 0.05 ; pad = 0.03 ; lu = 0.5 1115 | if np.abs(zevmax) == 1e-35: zevmax=0. 1116 | if np.abs(zevmin) == 1e-35: zevmin=0. 1117 | zelevpal = np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])) 1118 | clb = Figure.colorbar(fig,c,orientation=orientation,format=self.fmt,ticks=zelevpal,\ 1119 | fraction=frac,pad=pad,spacing='proportional') 1120 | #clb.set_label(fieldlab) 1121 | 1122 | # wind vectors 1123 | if incwind: 1124 | if isproj: x2d,y2d = x,y 1125 | else: [x2d,y2d] = np.meshgrid(lon,lat) 1126 | wcolor = str(self.trans) # trans=0 black, trans=100 white 1127 | yeah.quiver(x2d,y2d,np.transpose(windx),np.transpose(windy),color=wcolor) 1128 | 1129 | # add a point (TBD: text, use ax.annotate) 1130 | if (self.lonpoint is not None) and (self.latpoint is not None): 1131 | xpt,ypt = yeah(self.lonpoint,self.latpoint) # compute the native map projection coordinates 1132 | yeah.plot(xpt,ypt,'go',markersize=8) # plot filled circle at the location 1133 | 1134 | # operation on axis: title, labels, ticks, etc. 1135 | ax = fig.gca() 1136 | rcParams['axes.titlesize'] = rcParams['font.size'] 1137 | ax.set_title(fieldlab) 1138 | if not isproj: 1139 | ax.set_ylabel("Latitude") ; ax.set_xlabel("Longitude") 1140 | # make intervals 1141 | self.makeinterv() 1142 | ax.set_xticks(np.arange(-360,361,self.loninterv)) ; ax.set_xbound(lower=self.lons, upper=self.lone) 1143 | ax.set_yticks(np.arange(-90,91,self.latinterv)) ; ax.set_ybound(lower=self.lats, upper=self.late) 1144 | ax.set_xlim(xmin=-180.,xmax=180.) 1145 | 1146 | ## titles and final production 1147 | self.gettitle() 1148 | #ax.set_title(self.title,x=0.5,y=1.05) 1149 | #ax.set_xlabel('\n'+self.ack,x=0.5,y=0.05) 1150 | 1151 | fig.text(0.5, 0.95, self.title, ha='center', transform=fig.gca().transAxes, fontweight='bold') 1152 | fig.text(0.5, 0.01, self.ack, ha='center') 1153 | canvas = FigureCanvasAgg(fig) 1154 | # The size * the dpi gives the final image size 1155 | # a4"x4" image * 80 dpi ==> 320x320 pixel image 1156 | canvas.print_figure(figname, dpi=self.dpi) 1157 | #, bbox_inches='tight') removes title. and ax.set_title cannot set a global title for multiplots. 1158 | 1159 | 1160 | 1161 | def htmlplot2d(self,tabtodo,figname="temp.png"): 1162 | ### complete 2D figure with possible multiplots 1163 | ### added in 10/2012 for online MCD 1164 | ### see http://www.dalkescientific.com/writings/diary/archive/2005/04/23/matplotlib_without_gui.html 1165 | import mcdcomp as mcdcomp 1166 | from matplotlib import rcParams 1167 | from matplotlib.figure import Figure 1168 | from matplotlib.backends.backend_agg import FigureCanvasAgg 1169 | from matplotlib.cm import get_cmap 1170 | if isinstance(tabtodo,np.str): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 1171 | if isinstance(tabtodo,np.int): tabtodo=[tabtodo] ## so that asking one element without [] is possible. 1172 | 1173 | fig = mcdcomp.setfig(len(tabtodo)) 1174 | subv,subh = mcdcomp.definesubplot( len(tabtodo) , fig ) 1175 | 1176 | ####################### 1177 | self.query2d(self) 1178 | ####################### 1179 | 1180 | for i in range(len(tabtodo)): 1181 | yeah = fig.add_subplot(subv,subh,i+1) 1182 | choice = tabtodo[i] 1183 | 1184 | (field, fieldlab) = self.definefield(choice) 1185 | 1186 | colorb=self.colorm ; ndiv=20 1187 | 1188 | ## define field. bound field. 1189 | what_I_plot = np.transpose(field) 1190 | zevmin,zevmax,limtype = mcdcomp.setbounds(what_I_plot,vmin=self.min2d,vmax=self.max2d) 1191 | ## define contour field levels. define color palette 1192 | ticks = ndiv + 1 1193 | zelevels = np.linspace(zevmin,zevmax,ticks) 1194 | if zevmin==zevmax: # handle case where all values of the array are the same 1195 | zelevels = np.linspace(zevmin*0.9,zevmax*1.1,ticks) 1196 | palette = get_cmap(name=colorb) 1197 | # contour field 1198 | c = yeah.contourf( self.xcoord, self.ycoord, what_I_plot, zelevels, cmap = palette, extend=limtype ) 1199 | if np.abs(zevmax) == 1e-35: zevmax=0. 1200 | if np.abs(zevmin) == 1e-35: zevmin=0. 1201 | clb = Figure.colorbar(fig,c,orientation='vertical',format=self.fmt,ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21]))) 1202 | #clb.set_label(fieldlab) 1203 | ax = fig.gca() ; ax.set_ylabel(self.ylabel) ; ax.set_xlabel(self.xlabel) 1204 | rcParams['axes.titlesize'] = rcParams['font.size'] 1205 | ax.set_title(fieldlab) 1206 | 1207 | self.makeinterv() 1208 | if self.lons is not None: 1209 | if self.xdates is not None: 1210 | ax.set_yticks(np.arange(-360,361,self.loninterv)) ; ax.set_ybound(lower=self.lons, upper=self.lone) 1211 | else: 1212 | ax.set_xticks(np.arange(-360,361,self.loninterv)) ; ax.set_xbound(lower=self.lons, upper=self.lone) 1213 | elif self.lats is not None: 1214 | if self.xdates is not None: 1215 | ax.set_yticks(np.arange(-90,91,self.latinterv)) ; ax.set_ybound(lower=self.lats, upper=self.late) 1216 | else: 1217 | ax.set_xticks(np.arange(-90,91,self.latinterv)) ; ax.set_xbound(lower=self.lats, upper=self.late) 1218 | 1219 | if self.locts is not None: 1220 | if self.xzs is not None: 1221 | ax.set_xticks(np.arange(0,26,2)) ; ax.set_xbound(lower=self.locts, upper=self.locte) 1222 | else: 1223 | ax.set_yticks(np.arange(0,26,2)) ; ax.set_ybound(lower=self.locts, upper=self.locte) 1224 | elif self.xdates is not None: 1225 | ax.set_xticks(np.arange(0,361,30)) ; ax.set_xbound(lower=self.xdates, upper=self.xdatee) 1226 | 1227 | if self.zkey == 4 and self.xzs is not None: 1228 | ax.set_yscale('log') ; ax.set_ylim(ax.get_ylim()[::-1]) 1229 | else: 1230 | #ax.set_yticks(np.arange(self.xzs,self.xze,10000.)) ; 1231 | ax.set_ybound(lower=self.xzs, upper=self.xze) 1232 | 1233 | self.gettitle() 1234 | fig.text(0.5, 0.95, self.title, ha='center', transform=fig.gca().transAxes, fontweight='bold') 1235 | fig.text(0.5, 0.01, self.ack, ha='center') 1236 | canvas = FigureCanvasAgg(fig) 1237 | # The size * the dpi gives the final image size 1238 | # a4"x4" image * 80 dpi ==> 320x320 pixel image 1239 | canvas.print_figure(figname, dpi=self.dpi) 1240 | 1241 | ### TODO: makeplot2d, plot2d, passer plot settings 1242 | 1243 | -------------------------------------------------------------------------------- /mcdcomp.py: -------------------------------------------------------------------------------- 1 | ## set colorbar-type and value limits 2 | def setbounds(field,vmin=None,vmax=None): 3 | import numpy as np 4 | limtype = "neither" 5 | w = np.where(np.isnan(field) == False) 6 | fieldclean = field[w] 7 | if vmin is None and vmax is None: 8 | vmin = np.min(fieldclean) - 1.e-35 # epsilon to avoid blank spaces 9 | vmax = np.max(fieldclean) + 1.e-35 # epsilon to avoid blank spaces 10 | elif vmin is None: 11 | vmin = np.min(fieldclean) 12 | if vmax < np.max(fieldclean): 13 | limtype = "max" 14 | elif vmax is None: 15 | vmax = np.max(fieldclean) 16 | if vmin > np.min(fieldclean): 17 | limtype = "min" 18 | else: 19 | mintoosmall = vmin < np.min(fieldclean) 20 | maxtoohigh = vmax > np.max(fieldclean) 21 | if mintoosmall and maxtoohigh: 22 | limtype = "neither" 23 | elif mintoosmall: 24 | limtype = "max" 25 | elif maxtoohigh: 26 | limtype = "min" 27 | else: 28 | limtype = "both" 29 | return vmin,vmax,limtype 30 | 31 | ## set size of figure for optimal rendering 32 | def setfig(howmanyplots, proj=None): 33 | from matplotlib.figure import Figure 34 | ## 35 | if proj is None: 36 | squared = False 37 | else: 38 | squared = proj in ["npstere","spstere","ortho"] 39 | ## 40 | if howmanyplots == 1: 41 | if squared: fig = Figure(figsize=(10,10)) 42 | else: fig = Figure(figsize=(16,8)) 43 | elif howmanyplots == 2: 44 | if squared: fig = Figure(figsize=(7,14)) 45 | else: fig = Figure(figsize=(10,12)) 46 | elif howmanyplots == 3: 47 | if squared: fig = Figure(figsize=(7,21)) 48 | else: fig = Figure(figsize=(8,16)) 49 | elif howmanyplots == 4: 50 | if squared: fig = Figure(figsize=(10,10)) 51 | else: fig = Figure(figsize=(24,12)) 52 | return fig 53 | 54 | 55 | ################################################################ 56 | ################################################################ 57 | 58 | 59 | ## Those are additional functions 60 | ## Useful only for plots with mcd.py 61 | ## This is not intended to be improved 62 | ## -- instead planetoplot will be used one day 63 | 64 | def min (field,axis=None): 65 | import numpy as np 66 | if field is None: return None 67 | if type(field).__name__=='MaskedArray': 68 | field.set_fill_value(np.NaN) 69 | return np.ma.array(field).min(axis=axis) 70 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')): 71 | return np.ma.masked_invalid(field).min(axis=axis) 72 | else: return np.array(field).min(axis=axis) 73 | 74 | def max (field,axis=None): 75 | import numpy as np 76 | if field is None: return None 77 | if type(field).__name__=='MaskedArray': 78 | field.set_fill_value(np.NaN) 79 | return np.ma.array(field).max(axis=axis) 80 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')): 81 | return np.ma.masked_invalid(field).max(axis=axis) 82 | else: return np.array(field).max(axis=axis) 83 | 84 | def mean (field,axis=None): 85 | import numpy as np 86 | if field is None: return None 87 | else: 88 | if type(field).__name__=='MaskedArray': 89 | field.set_fill_value(np.NaN) 90 | zout=np.ma.array(field).mean(axis=axis) 91 | if axis is not None: 92 | zout.set_fill_value(np.NaN) 93 | return zout.filled() 94 | else:return zout 95 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')): 96 | zout=np.ma.masked_invalid(field).mean(axis=axis) 97 | if axis is not None: 98 | zout.set_fill_value([np.NaN]) 99 | return zout.filled() 100 | else:return zout 101 | else: 102 | return np.array(field).mean(axis=axis) 103 | 104 | def sum (field,axis=None): 105 | import numpy as np 106 | if field is None: return None 107 | else: 108 | if type(field).__name__=='MaskedArray': 109 | field.set_fill_value(np.NaN) 110 | zout=np.ma.array(field).sum(axis=axis) 111 | if axis is not None: 112 | zout.set_fill_value(np.NaN) 113 | return zout.filled() 114 | else:return zout 115 | elif (np.isnan(np.sum(field)) and (type(field).__name__ not in 'MaskedArray')): 116 | zout=np.ma.masked_invalid(field).sum(axis=axis) 117 | if axis is not None: 118 | zout.set_fill_value([np.NaN]) 119 | return zout.filled() 120 | else:return zout 121 | else: 122 | return np.array(field).sum(axis=axis) 123 | 124 | ################################################################# 125 | ################################################################# 126 | ################################################################# 127 | 128 | ## Author: AS, AC, JL 129 | def whatkindfile (nc): 130 | typefile = 'gcm' # default 131 | if 'controle' in nc.variables: typefile = 'gcm' 132 | elif 'phisinit' in nc.variables: typefile = 'gcm' 133 | elif 'phis' in nc.variables: typefile = 'gcm' 134 | elif 'time_counter' in nc.variables: typefile = 'earthgcm' 135 | elif hasattr(nc,'START_DATE'): typefile = 'meso' 136 | elif 'HGT_M' in nc.variables: typefile = 'geo' 137 | elif hasattr(nc,'institution'): 138 | if "European Centre" in getattr(nc,'institution'): typefile = 'ecmwf' 139 | return typefile 140 | 141 | ## Author: AS + TN 142 | def definesubplot ( numplot, fig, ipreferline=False): 143 | from matplotlib.pyplot import rcParams 144 | rcParams['font.size'] = 12. ## default (important for multiple calls) 145 | fc = 1.33 146 | if numplot <= 0: 147 | subv = 99999 148 | subh = 99999 149 | elif numplot == 1: 150 | subv = 1 151 | subh = 1 152 | elif numplot == 2: 153 | subv = 2 #1 #2 154 | subh = 1 #2 #1 155 | fig.subplots_adjust(wspace = 0.35*fc) 156 | fig.subplots_adjust(hspace = 0.3*fc) 157 | #rcParams['font.size'] = int( rcParams['font.size'] * 3. / 4. ) 158 | elif numplot == 3: 159 | subv = 3 160 | subh = 1 161 | fig.subplots_adjust(hspace = 0.25*fc) 162 | fig.subplots_adjust(wspace = 0.35*fc) 163 | if ipreferline: subv = 1 ; subh = 3 ; fig.subplots_adjust(wspace = 0.35*fc) 164 | #rcParams['font.size'] = int( rcParams['font.size'] * 3. / 4. ) 165 | elif numplot == 4: 166 | subv = 2 167 | subh = 2 168 | #fig.subplots_adjust(wspace = 0.4, hspace = 0.6) 169 | fig.subplots_adjust(wspace = 0.25*fc, hspace = 0.3*fc) 170 | #rcParams['font.size'] = int( rcParams['font.size'] * 3. / 4. ) 171 | elif numplot <= 6: 172 | subv = 2 173 | subh = 3 174 | #fig.subplots_adjust(wspace = 0.4, hspace = 0.0) 175 | fig.subplots_adjust(wspace = 0.5*fc, hspace = 0.3*fc) 176 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. ) 177 | elif numplot <= 8: 178 | subv = 2 179 | subh = 4 180 | fig.subplots_adjust(wspace = 0.3*fc, hspace = 0.3*fc) 181 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. ) 182 | elif numplot <= 9: 183 | subv = 3 184 | subh = 3 185 | fig.subplots_adjust(wspace = 0.3*fc, hspace = 0.3*fc) 186 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. ) 187 | elif numplot <= 12: 188 | subv = 3 189 | subh = 4 190 | fig.subplots_adjust(wspace = 0, hspace = 0.1*fc) 191 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. ) 192 | elif numplot <= 16: 193 | subv = 4 194 | subh = 4 195 | fig.subplots_adjust(wspace = 0.3*fc, hspace = 0.3*fc) 196 | rcParams['font.size'] = int( rcParams['font.size'] * 1. / 2. ) 197 | else: 198 | print "number of plot supported: 1 to 16" 199 | exit() 200 | return subv,subh 201 | 202 | ## Author: AS 203 | def getproj (nc): 204 | typefile = whatkindfile(nc) 205 | if typefile in ['meso','geo']: 206 | ### (il faudrait passer CEN_LON dans la projection ?) 207 | map_proj = getattr(nc, 'MAP_PROJ') 208 | cen_lat = getattr(nc, 'CEN_LAT') 209 | if map_proj == 2: 210 | if cen_lat > 10.: 211 | proj="npstere" 212 | #print "NP stereographic polar domain" 213 | else: 214 | proj="spstere" 215 | #print "SP stereographic polar domain" 216 | elif map_proj == 1: 217 | #print "lambert projection domain" 218 | proj="lcc" 219 | elif map_proj == 3: 220 | #print "mercator projection" 221 | proj="merc" 222 | else: 223 | proj="merc" 224 | elif typefile in ['gcm']: proj="cyl" ## pb avec les autres (de trace derriere la sphere ?) 225 | else: proj="ortho" 226 | return proj 227 | 228 | ## Author: AS 229 | def ptitle (name): 230 | from matplotlib.pyplot import title 231 | title(name) 232 | print name 233 | 234 | ## Author: AS 235 | def polarinterv (lon2d,lat2d): 236 | import numpy as np 237 | wlon = [np.min(lon2d),np.max(lon2d)] 238 | ind = np.array(lat2d).shape[0] / 2 ## to get a good boundlat and to get the pole 239 | wlat = [np.min(lat2d[ind,:]),np.max(lat2d[ind,:])] 240 | return [wlon,wlat] 241 | 242 | ## Author: AS 243 | def simplinterv (lon2d,lat2d): 244 | import numpy as np 245 | return [[np.min(lon2d),np.max(lon2d)],[np.min(lat2d),np.max(lat2d)]] 246 | 247 | ## Author: AS 248 | def wrfinterv (lon2d,lat2d): 249 | nx = len(lon2d[0,:])-1 250 | ny = len(lon2d[:,0])-1 251 | lon1 = lon2d[0,0] 252 | lon2 = lon2d[nx,ny] 253 | lat1 = lat2d[0,0] 254 | lat2 = lat2d[nx,ny] 255 | if abs(0.5*(lat1+lat2)) > 60.: wider = 0.5 * (abs(lon1)+abs(lon2)) * 0.1 256 | else: wider = 0. 257 | if lon1 < lon2: wlon = [lon1, lon2 + wider] 258 | else: wlon = [lon2, lon1 + wider] 259 | if lat1 < lat2: wlat = [lat1, lat2] 260 | else: wlat = [lat2, lat1] 261 | return [wlon,wlat] 262 | 263 | ## Author: AS 264 | def makeplotres (filename,res=None,pad_inches_value=0.25,folder='',disp=True,ext='png',erase=False): 265 | import matplotlib.pyplot as plt 266 | from os import system 267 | addstr = "" 268 | if res is not None: 269 | res = int(res) 270 | addstr = "_"+str(res) 271 | name = filename+addstr+"."+ext 272 | if folder != '': name = folder+'/'+name 273 | plt.savefig(name,dpi=res,bbox_inches='tight',pad_inches=pad_inches_value) 274 | if disp: display(name) 275 | if ext in ['eps','ps','svg']: system("tar czvf "+name+".tar.gz "+name+" ; rm -f "+name) 276 | if erase: system("mv "+name+" to_be_erased") 277 | return 278 | 279 | ## Author: AS + AC 280 | def getcoorddef ( nc ): 281 | import numpy as np 282 | ## getcoord2d for predefined types 283 | typefile = whatkindfile(nc) 284 | if typefile in ['meso']: 285 | if '9999' not in getattr(nc,'START_DATE') : 286 | ## regular mesoscale 287 | [lon2d,lat2d] = getcoord2d(nc) 288 | else: 289 | ## idealized mesoscale 290 | nx=getattr(nc,'WEST-EAST_GRID_DIMENSION') 291 | ny=getattr(nc,'SOUTH-NORTH_GRID_DIMENSION') 292 | dlat=getattr(nc,'DX') 293 | ## this is dirty because Martian-specific 294 | # ... but this just intended to get "lat-lon" like info 295 | falselon = np.arange(-dlat*(nx-1)/2.,dlat*(nx-1)/2.,dlat)/60000. 296 | falselat = np.arange(-dlat*(ny-1)/2.,dlat*(ny-1)/2.,dlat)/60000. 297 | [lon2d,lat2d] = np.meshgrid(falselon,falselat) ## dummy coordinates 298 | print "WARNING: domain plot artificially centered on lat,lon 0,0" 299 | elif typefile in ['gcm','earthgcm','ecmwf']: 300 | #### n est ce pas nc.variables ? 301 | if "longitude" in nc.dimensions: dalon = "longitude" 302 | elif "lon" in nc.dimensions: dalon = "lon" 303 | else: dalon = "nothing" 304 | if "latitude" in nc.dimensions: dalat = "latitude" 305 | elif "lat" in nc.dimensions: dalat = "lat" 306 | else: dalat = "nothing" 307 | [lon2d,lat2d] = getcoord2d(nc,nlat=dalat,nlon=dalon,is1d=True) 308 | elif typefile in ['geo']: 309 | [lon2d,lat2d] = getcoord2d(nc,nlat='XLAT_M',nlon='XLONG_M') 310 | return lon2d,lat2d 311 | 312 | ## Author: AS 313 | def getcoord2d (nc,nlat='XLAT',nlon='XLONG',is1d=False): 314 | import numpy as np 315 | if nlon == "nothing" or nlat == "nothing": 316 | print "NO LAT LON FIELDS. I AM TRYING MY BEST. I ASSUME GLOBAL FIELD." 317 | lon = np.linspace(-180.,180.,getdimfromvar(nc)[-1]) 318 | lat = np.linspace(-90.,90.,getdimfromvar(nc)[-2]) 319 | [lon2d,lat2d] = np.meshgrid(lon,lat) 320 | else: 321 | if is1d: 322 | lat = nc.variables[nlat][:] 323 | lon = nc.variables[nlon][:] 324 | [lon2d,lat2d] = np.meshgrid(lon,lat) 325 | else: 326 | lat = nc.variables[nlat][0,:,:] 327 | lon = nc.variables[nlon][0,:,:] 328 | [lon2d,lat2d] = [lon,lat] 329 | return lon2d,lat2d 330 | 331 | ## Author: AS 332 | def getdimfromvar (nc): 333 | varinfile = nc.variables.keys() 334 | dim = nc.variables[varinfile[-1]].shape ## usually the last variable is 4D or 3D 335 | return dim 336 | 337 | ## Author: AS 338 | def vectorfield (u, v, x, y, stride=3, scale=15., factor=250., color='black', csmooth=1, key=True): 339 | ## scale regle la reference du vecteur 340 | ## factor regle toutes les longueurs (dont la reference). l'AUGMENTER pour raccourcir les vecteurs. 341 | import matplotlib.pyplot as plt 342 | import numpy as np 343 | #posx = np.min(x) - np.std(x) / 10. 344 | #posy = np.min(y) - np.std(y) / 10. 345 | posx = np.min(x) 346 | posy = np.min(y) - 4.*np.std(y) / 10. 347 | widthvec = 0.003 #0.005 #0.003 348 | q = plt.quiver( x[::stride,::stride],\ 349 | y[::stride,::stride],\ 350 | u[::stride,::stride],\ 351 | v[::stride,::stride],\ 352 | angles='xy',color=color,pivot='middle',\ 353 | scale=factor,width=widthvec ) 354 | if color in ['white','yellow']: kcolor='black' 355 | else: kcolor=color 356 | if key: p = plt.quiverkey(q,posx,posy,scale,\ 357 | str(int(scale)),coordinates='data',color=kcolor,labelpos='S',labelsep = 0.03) 358 | return 359 | 360 | ## Author: AS 361 | def display (name): 362 | from os import system 363 | system("display "+name+" > /dev/null 2> /dev/null &") 364 | return name 365 | 366 | ## Author: AS 367 | def findstep (wlon): 368 | steplon = int((wlon[1]-wlon[0])/4.) #3 369 | step = 120. 370 | while step > steplon and step > 15. : step = step / 2. 371 | if step <= 15.: 372 | while step > steplon and step > 5. : step = step - 5. 373 | if step <= 5.: 374 | while step > steplon and step > 1. : step = step - 1. 375 | if step <= 1.: 376 | step = 1. 377 | return step 378 | 379 | ## Author: AS 380 | def define_proj (char,wlon,wlat,back=None,blat=None,blon=None): 381 | from mpl_toolkits.basemap import Basemap 382 | import numpy as np 383 | import matplotlib as mpl 384 | meanlon = 0.5*(wlon[0]+wlon[1]) 385 | meanlat = 0.5*(wlat[0]+wlat[1]) 386 | zewidth = np.abs(wlon[0]-wlon[1])*60000.*np.cos(3.14*meanlat/180.) 387 | zeheight = np.abs(wlat[0]-wlat[1])*60000. 388 | if blat is None: 389 | ortholat=meanlat 390 | if wlat[0] >= 80.: blat = -40. 391 | elif wlat[1] <= -80.: blat = -40. 392 | elif wlat[1] >= 0.: blat = wlat[0] 393 | elif wlat[0] <= 0.: blat = wlat[1] 394 | else: ortholat=blat 395 | if blon is None: ortholon=meanlon 396 | else: ortholon=blon 397 | h = 50. ## en km 398 | radius = 3397200. 399 | if char == "cyl": m = Basemap(rsphere=radius,projection='cyl',\ 400 | llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1]) 401 | elif char == "moll": m = Basemap(rsphere=radius,projection='moll',lon_0=meanlon) 402 | elif char == "ortho": m = Basemap(rsphere=radius,projection='ortho',lon_0=ortholon,lat_0=ortholat) 403 | elif char == "lcc": m = Basemap(rsphere=radius,projection='lcc',lat_1=meanlat,lat_0=meanlat,lon_0=meanlon,\ 404 | width=zewidth,height=zeheight) 405 | #llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1]) 406 | elif char == "npstere": m = Basemap(rsphere=radius,projection='npstere', boundinglat=blat, lon_0=0.) 407 | elif char == "spstere": m = Basemap(rsphere=radius,projection='spstere', boundinglat=blat, lon_0=180.) 408 | elif char == "nplaea": m = Basemap(rsphere=radius,projection='nplaea', boundinglat=wlat[0], lon_0=meanlon) 409 | elif char == "laea": m = Basemap(rsphere=radius,projection='laea',lon_0=meanlon,lat_0=meanlat,lat_ts=meanlat,\ 410 | width=zewidth,height=zeheight) 411 | #llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1]) 412 | elif char == "nsper": m = Basemap(rsphere=radius,projection='nsper',lon_0=meanlon,lat_0=meanlat,satellite_height=h*1000.) 413 | elif char == "merc": m = Basemap(rsphere=radius,projection='merc',lat_ts=0.,\ 414 | llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1]) 415 | elif char == "geos": m = Basemap(rsphere=radius,projection='geos',lon_0=meanlon) 416 | elif char == "robin": m = Basemap(rsphere=radius,projection='robin',lon_0=0) 417 | elif char == "cass": 418 | if zewidth > 60000.: ## approx. more than one degree 419 | m = Basemap(rsphere=radius,projection='cass',\ 420 | lon_0=meanlon,lat_0=meanlat,\ 421 | width=zewidth,height=zeheight) 422 | else: 423 | m = Basemap(rsphere=radius,projection='cass',\ 424 | lon_0=meanlon,lat_0=meanlat,\ 425 | llcrnrlat=wlat[0],urcrnrlat=wlat[1],llcrnrlon=wlon[0],urcrnrlon=wlon[1]) 426 | else: errormess("projection not supported.") 427 | fontsizemer = int(mpl.rcParams['font.size']*3./4.) 428 | if zewidth > 60000.: 429 | if char in ["cyl","lcc","merc","nsper","laea"]: step = findstep(wlon) 430 | else: step = 10. 431 | steplon = step*2. 432 | else: 433 | print "very small domain !" 434 | steplon = 0.5 435 | step = 0.5 436 | zecolor ='grey' 437 | zelinewidth = 1 438 | zelatmax = 80. 439 | if meanlat > 75.: zelatmax = 90. ; step = step/2. ; steplon = steplon*2. 440 | # # to show gcm grid: 441 | # #zecolor = 'r' 442 | # #zelinewidth = 1 443 | # #step = 180./48. 444 | # #steplon = 360./64. 445 | # #zelatmax = 90. - step/3 446 | # if char not in ["moll","robin"]: 447 | # if wlon[1]-wlon[0] < 2.: ## LOCAL MODE 448 | # m.drawmeridians(np.r_[-1.:1.:0.05], labels=[0,0,0,1], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, fmt='%5.2f') 449 | # m.drawparallels(np.r_[-1.:1.:0.05], labels=[1,0,0,0], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, fmt='%5.2f') 450 | # else: ## GLOBAL OR REGIONAL MODE 451 | # m.drawmeridians(np.r_[-180.:180.:steplon], labels=[0,0,0,1], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, latmax=zelatmax) 452 | # m.drawparallels(np.r_[-90.:90.:step], labels=[1,0,0,0], color=zecolor, linewidth=zelinewidth, fontsize=fontsizemer, latmax=zelatmax) 453 | if back is not None: 454 | if back not in ["coast","sea"]: m.warpimage(marsmap(back),scale=0.75) 455 | elif back == "coast": m.drawcoastlines() 456 | elif back == "sea": m.drawlsmask(land_color='white',ocean_color='aqua') 457 | #if not back: 458 | # if not var: back = "mola" ## if no var: draw mola 459 | # elif typefile in ['mesoapi','meso','geo'] \ 460 | # and proj not in ['merc','lcc','nsper','laea']: back = "molabw" ## if var but meso: draw molabw 461 | # else: pass ## else: draw None 462 | return m 463 | 464 | ### Author: AS 465 | #def calculate_bounds(field,vmin=None,vmax=None): 466 | # import numpy as np 467 | # ind = np.where(field < 9e+35) 468 | # fieldcalc = field[ ind ] # la syntaxe compacte ne marche si field est un tuple 469 | # ### 470 | # dev = np.std(fieldcalc)*3.0 471 | # ### 472 | # if vmin is None: zevmin = mean(fieldcalc) - dev 473 | # else: zevmin = vmin 474 | # ### 475 | # if vmax is None: zevmax = mean(fieldcalc) + dev 476 | # else: zevmax = vmax 477 | # if vmin == vmax: 478 | # zevmin = mean(fieldcalc) - dev ### for continuity 479 | # zevmax = mean(fieldcalc) + dev ### for continuity 480 | # ### 481 | # if zevmin < min(fieldcalc): zevmin = min(fieldcalc) 482 | # if zevmax > max(fieldcalc): zevmax = max(fieldcalc) 483 | # ##if zevmin < 0. and min(fieldcalc) > 0.: zevmin = 0. 484 | # ##print "BOUNDS field ", min(fieldcalc), max(fieldcalc), " //// adopted", zevmin, zevmax 485 | # return zevmin, zevmax 486 | 487 | ### Author: AS 488 | #def bounds(what_I_plot,zevmin,zevmax): 489 | # ### might be convenient to add the missing value in arguments 490 | # #what_I_plot[ what_I_plot < zevmin ] = zevmin#*(1. + 1.e-7) 491 | # if zevmin < 0: what_I_plot[ what_I_plot < zevmin*(1. - 1.e-7) ] = zevmin*(1. - 1.e-7) 492 | # else: what_I_plot[ what_I_plot < zevmin*(1. + 1.e-7) ] = zevmin*(1. + 1.e-7) 493 | # #print "NEW MIN ", min(what_I_plot) 494 | # what_I_plot[ what_I_plot > 9e+35 ] = -9e+35 495 | # what_I_plot[ what_I_plot > zevmax ] = zevmax*(1. - 1.e-7) 496 | # #print "NEW MAX ", max(what_I_plot) 497 | # return what_I_plot 498 | 499 | ## a function to solve the problem with blank bounds ! 500 | ## ------------------------------- 501 | #def bounds(what_I_plot,zevmin,zevmax,miss=9e+35): 502 | # import numpy as np 503 | # small_enough = 1.e-7 504 | # if zevmin < 0: what_I_plot[ what_I_plot < zevmin*(1.-small_enough) ] = zevmin*(1.-small_enough) 505 | # else: what_I_plot[ what_I_plot < zevmin*(1.+small_enough) ] = zevmin*(1.+small_enough) 506 | # what_I_plot[ what_I_plot > miss ] = -miss 507 | # what_I_plot[ what_I_plot > zevmax ] = zevmax*(1.-small_enough) 508 | # ## test 509 | # what_I_plot[ np.abs(what_I_plot) < small_enough ] = small_enough 510 | # return what_I_plot 511 | 512 | ## Author: AS 513 | def nolow(what_I_plot): 514 | lim = 0.15*0.5*(abs(max(what_I_plot))+abs(min(what_I_plot))) 515 | print "NO PLOT BELOW VALUE ", lim 516 | what_I_plot [ abs(what_I_plot) < lim ] = 1.e40 517 | return what_I_plot 518 | 519 | ## Author: AS 520 | def zoomset (wlon,wlat,zoom): 521 | dlon = abs(wlon[1]-wlon[0])/2. 522 | dlat = abs(wlat[1]-wlat[0])/2. 523 | [wlon,wlat] = [ [wlon[0]+zoom*dlon/100.,wlon[1]-zoom*dlon/100.],\ 524 | [wlat[0]+zoom*dlat/100.,wlat[1]-zoom*dlat/100.] ] 525 | print "ZOOM %",zoom,wlon,wlat 526 | return wlon,wlat 527 | 528 | ## Author: AS 529 | def definecolorvec (whichone="def"): 530 | whichcolor = { \ 531 | "def": "black",\ 532 | "vis": "yellow",\ 533 | "vishires": "green",\ 534 | "molabw": "yellow",\ 535 | "mola": "black",\ 536 | "gist_heat": "white",\ 537 | "hot": "tk",\ 538 | "gist_rainbow": "black",\ 539 | "spectral": "black",\ 540 | "gray": "red",\ 541 | "PuBu": "black",\ 542 | "titan": "red",\ 543 | } 544 | if whichone not in whichcolor: 545 | whichone = "def" 546 | return whichcolor[whichone] 547 | 548 | ## Author: AS 549 | def marsmap (whichone="vishires"): 550 | from os import uname 551 | mymachine = uname()[1] 552 | ### not sure about speed-up with this method... looks the same 553 | if "lmd.jussieu.fr" in mymachine: domain = "/u/aslmd/WWW/maps/" 554 | elif "aymeric-laptop" in mymachine: domain = "/home/aymeric/Dropbox/Public/" 555 | else: domain = "http://www.lmd.jussieu.fr/~aslmd/maps/" 556 | whichlink = { \ 557 | #"vis": "http://maps.jpl.nasa.gov/pix/mar0kuu2.jpg",\ 558 | #"vishires": "http://www.lmd.jussieu.fr/~aslmd/maps/MarsMap_2500x1250.jpg",\ 559 | #"geolocal": "http://dl.dropbox.com/u/11078310/geolocal.jpg",\ 560 | #"mola": "http://www.lns.cornell.edu/~seb/celestia/mars-mola-2k.jpg",\ 561 | #"molabw": "http://dl.dropbox.com/u/11078310/MarsElevation_2500x1250.jpg",\ 562 | "thermalday": domain+"thermalday.jpg",\ 563 | "thermalnight": domain+"thermalnight.jpg",\ 564 | "tesalbedo": domain+"tesalbedo.jpg",\ 565 | "vis": domain+"mar0kuu2.jpg",\ 566 | "vishires": domain+"MarsMap_2500x1250.jpg",\ 567 | "geolocal": domain+"geolocal.jpg",\ 568 | "mola": domain+"mars-mola-2k.jpg",\ 569 | "molabw": domain+"MarsElevation_2500x1250.jpg",\ 570 | "clouds": "http://www.johnstonsarchive.net/spaceart/marswcloudmap.jpg",\ 571 | "jupiter": "http://www.mmedia.is/~bjj/data/jupiter_css/jupiter_css.jpg",\ 572 | "jupiter_voy": "http://www.mmedia.is/~bjj/data/jupiter/jupiter_vgr2.jpg",\ 573 | #"bw": domain+"EarthElevation_2500x1250.jpg",\ 574 | "bw": "http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthElevation_2500x1250.jpg",\ 575 | "contrast": "http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthMapAtmos_2500x1250.jpg",\ 576 | "nice": "http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/earthmap1k.jpg",\ 577 | "blue": "http://eoimages.gsfc.nasa.gov/ve/2430/land_ocean_ice_2048.jpg",\ 578 | "blueclouds": "http://eoimages.gsfc.nasa.gov/ve/2431/land_ocean_ice_cloud_2048.jpg",\ 579 | "justclouds": "http://eoimages.gsfc.nasa.gov/ve/2432/cloud_combined_2048.jpg",\ 580 | "pluto": "http://www.boulder.swri.edu/~buie/pluto/pluto_all.png",\ 581 | "triton": "http://laps.noaa.gov/albers/sos/neptune/triton/triton_rgb_cyl_www.jpg",\ 582 | "titan": "http://laps.noaa.gov/albers/sos/saturn/titan/titan_rgb_cyl_www.jpg",\ 583 | #"titan": "http://laps.noaa.gov/albers/sos/celestia/titan_50.jpg",\ 584 | "titanuni": "http://maps.jpl.nasa.gov/pix/sat6fss1.jpg",\ 585 | "venus": "http://laps.noaa.gov/albers/sos/venus/venus4/venus4_rgb_cyl_www.jpg",\ 586 | "cosmic": "http://laps.noaa.gov/albers/sos/universe/wmap/wmap_rgb_cyl_www.jpg",\ 587 | } 588 | ### see http://www.mmedia.is/~bjj/planetary_maps.html 589 | if whichone not in whichlink: 590 | print "marsmap: choice not defined... you'll get the default one... " 591 | whichone = "vishires" 592 | return whichlink[whichone] 593 | 594 | #def earthmap (whichone): 595 | # if whichone == "contrast": whichlink="http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthMapAtmos_2500x1250.jpg" 596 | # elif whichone == "bw": whichlink="http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/EarthElevation_2500x1250.jpg" 597 | # elif whichone == "nice": whichlink="http://users.info.unicaen.fr/~karczma/TEACH/InfoGeo/Images/Planets/earthmap1k.jpg" 598 | # return whichlink 599 | 600 | ## Author: AS 601 | def latinterv (area="Whole"): 602 | list = { \ 603 | "Europe": [[ 20., 80.],[- 50., 50.]],\ 604 | "Central_America": [[-10., 40.],[ 230., 300.]],\ 605 | "Africa": [[-20., 50.],[- 50., 50.]],\ 606 | "Whole": [[-90., 90.],[-180., 180.]],\ 607 | "Southern_Hemisphere": [[-90., 60.],[-180., 180.]],\ 608 | "Northern_Hemisphere": [[-60., 90.],[-180., 180.]],\ 609 | "Tharsis": [[-30., 60.],[-170.,- 10.]],\ 610 | "Whole_No_High": [[-60., 60.],[-180., 180.]],\ 611 | "Chryse": [[-60., 60.],[- 60., 60.]],\ 612 | "North_Pole": [[ 50., 90.],[-180., 180.]],\ 613 | "Close_North_Pole": [[ 75., 90.],[-180., 180.]],\ 614 | "Far_South_Pole": [[-90.,-40.],[-180., 180.]],\ 615 | "South_Pole": [[-90.,-50.],[-180., 180.]],\ 616 | "Close_South_Pole": [[-90.,-75.],[-180., 180.]],\ 617 | "Sirenum_Crater_large": [[-46.,-34.],[-166.,-151.]],\ 618 | "Sirenum_Crater_small": [[-36.,-26.],[-168.,-156.]],\ 619 | "Rupes": [[ 72., 90.],[-120.,- 20.]],\ 620 | "Xanadu": [[-40., 20.],[ 40., 120.]],\ 621 | "Hyperboreae": [[ 80., 87.],[- 70.,- 10.]],\ 622 | } 623 | if area not in list: area = "Whole" 624 | [olat,olon] = list[area] 625 | return olon,olat 626 | 627 | ## Author : AS 628 | def maplatlon( lon,lat,field,\ 629 | proj="cyl",colorb="jet",ndiv=10,zeback=None,trans=0.6,title="",\ 630 | vecx=None,vecy=None,stride=2,vmin=None,vmax=None): 631 | ### an easy way to map a field over lat/lon grid 632 | import numpy as np 633 | import matplotlib.pyplot as mpl 634 | from matplotlib.cm import get_cmap 635 | ## get lon and lat in 2D version. get lat/lon intervals 636 | numdim = len(np.array(lon).shape) 637 | if numdim == 2: [lon2d,lat2d] = [lon,lat] 638 | elif numdim == 1: [lon2d,lat2d] = np.meshgrid(lon,lat) 639 | else: errormess("lon and lat arrays must be 1D or 2D") 640 | #[wlon,wlat] = latinterv() 641 | [wlon,wlat] = simplinterv(lon2d,lat2d) 642 | ## define projection and background. define x and y given the projection 643 | m = define_proj(proj,wlon,wlat,back=zeback,blat=None,blon=None) 644 | x, y = m(lon2d, lat2d) 645 | ## define field. bound field. 646 | what_I_plot = np.transpose(field) 647 | zevmin,zevmax,limtype = setbounds(what_I_plot,vmin=vmin,vmax=vmax) 648 | ## define contour field levels. define color palette 649 | ticks = ndiv + 1 650 | zelevels = np.linspace(zevmin,zevmax,ticks) 651 | palette = get_cmap(name=colorb) 652 | ## contour field 653 | m.contourf( x, y, what_I_plot, zelevels, cmap = palette, alpha = trans ) 654 | ## draw colorbar 655 | if proj in ['moll','cyl']: zeorientation="horizontal" ; zepad = 0.07 656 | else: zeorientation="vertical" ; zepad = 0.03 657 | daformat = "%.0f" 658 | zecb = mpl.colorbar( fraction=0.05,pad=zepad,format=daformat,orientation=zeorientation,\ 659 | ticks=np.linspace(zevmin,zevmax,num=min([ticks/2+1,21])),extend='neither',spacing='proportional' ) 660 | ## give a title 661 | if zeorientation == "horizontal": zecb.ax.set_xlabel(title) 662 | else: ptitle(title) 663 | ## draw vector 664 | if vecx is not None and vecy is not None: 665 | [vecx_frame,vecy_frame] = m.rotate_vector( np.transpose(vecx), np.transpose(vecy), lon2d, lat2d ) ## for metwinds 666 | vectorfield(vecx_frame, vecy_frame, x, y, stride=stride, csmooth=2,\ 667 | scale=30., factor=500., color=definecolorvec(colorb), key=True) 668 | ## scale regle la reference du vecteur. factor regle toutes les longueurs (dont la reference). l'AUGMENTER pour raccourcir les vecteurs. 669 | return 670 | -------------------------------------------------------------------------------- /netcdf/gfortran_netcdf4_fPIC: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | ze_netcdf=netcdf-4.0.1 4 | #ze_netcdf=netcdf-3.6.1 5 | 6 | #wget ftp://ftp.unidata.ucar.edu/pub/netcdf/$ze_netcdf.tar.gz 7 | wget ftp://ftp.unidata.ucar.edu/pub/netcdf/old/$ze_netcdf.tar.gz 8 | tar xzvf $ze_netcdf.tar.gz 9 | \rm $ze_netcdf.tar.gz 10 | 11 | export FC=gfortran 12 | export FFLAGS=" -O2 -fPIC" 13 | export F90=gfortran 14 | export FCFLAGS="-O2 -ffree-form -fPIC" 15 | export CPPFLAGS="" 16 | export CC=gcc 17 | export CFLAGS="-O2 -fPIC" 18 | export CXX=g++ 19 | export CXXFLAGS="-O2 -fPIC" 20 | 21 | mv $ze_netcdf gfortran_$ze_netcdf 22 | cd gfortran_$ze_netcdf 23 | PREFIX=$PWD 24 | if [[ "$ze_netcdf" == "netcdf-3.6.1" ]] 25 | then 26 | cd src 27 | fi 28 | 29 | ./configure --prefix=${PREFIX} #--disable-cxx 30 | make > make.log 2>&1 31 | make test > make.log 2>&1 32 | make install > make.log 2>&1 33 | -------------------------------------------------------------------------------- /netcdf/gfortran_netcdf4_fpic_old: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | fd="./" 4 | 5 | ################## 6 | 7 | # get absolute path 8 | here=$PWD 9 | cd $fd 10 | installfd=$PWD 11 | echo install in $installfd 12 | cd $here 13 | 14 | # download 15 | \rm -rf netcdf-4.0.1.tar.gz* 16 | \rm -rf netcdf-4.0.1 17 | wget ftp://ftp.unidata.ucar.edu/pub/netcdf/old/netcdf-4.0.1.tar.gz 18 | tar xzvf netcdf-4.0.1.tar.gz > /dev/null 2>&1 19 | 20 | # make netcdf library 21 | cd netcdf-4.0.1 22 | pwd 23 | 24 | export FC=gfortran 25 | export FFLAGS=" -O2" 26 | export F90=gfortran 27 | export FCFLAGS="-O2 -ffree-form" 28 | export CPPFLAGS="" 29 | export CC=gcc 30 | export CFLAGS="-O2" 31 | export CXX=g++ 32 | export CXXFLAGS="-O2" 33 | 34 | \rm -rf *.log 35 | echo ...configure 36 | ./configure --with-pic --prefix=$installfd > $installfd/configure.log 2>&1 37 | echo ...make 38 | make > $installfd/make.log 2>&1 39 | echo ...test 40 | make test > $installfd/make_test.log 2>&1 41 | echo ...install 42 | make install > $installfd/make_install.log 2>&1 43 | 44 | 45 | -------------------------------------------------------------------------------- /patch.txt: -------------------------------------------------------------------------------- 1 | usercode ''' 2 | PyDict_SetItem(d,PyString_FromString("dataloc"),PyString_FromString(dataloc)); 3 | PyDict_SetItem(d,PyString_FromString("dataver"),PyString_FromString(dataver)); 4 | ''' 5 | -------------------------------------------------------------------------------- /perso/ddcriterion.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from mcd import mcd 3 | import numpy as np 4 | import ppplot 5 | 6 | dd = mcd() 7 | dd.toversion5() 8 | dd.fixedlt = True 9 | dd.loct = 13. 10 | dd.zkey = 3 11 | dd.xz = 20. 12 | 13 | for ls in [45,90,135,180,225,270]: 14 | 15 | print ls 16 | dd.xdate = ls 17 | dd.latlon(ndx=64,ndy=48) 18 | 19 | maxw = dd.extvartab[:,:,47] 20 | z0 = dd.extvartab[:,:,29] 21 | stress = dd.extvartab[:,:,51] 22 | rho = dd.extvartab[:,:,92] 23 | hgt = dd.extvartab[:,:,4] 24 | 25 | tsurf = dd.extvartab[:,:,15] 26 | temp = dd.extvartab[:,:,93] 27 | 28 | 29 | ustar = np.sqrt(stress/rho) 30 | wstar = maxw / 2.75 31 | 32 | limsmall = 0.5 33 | ustar[np.where(ustar 5.) 40 | #there was an error here! 41 | tol = 50. 42 | ind = np.where(100. * ddwinderror / ddwind > tol) ; ddwind[ind] = np.NaN 43 | print "2. error on wind too large" 44 | print yorgl[0][ind] 45 | print ddwinderror[ind] 46 | ind = np.where(100. * ddheighterror / ddheight > tol) ; ddwind[ind] = np.NaN 47 | print "3. error on height too large" 48 | print yorgl[0][ind] 49 | print ddheighterror[ind] 50 | ## one record is doubtful according to Reiss 51 | ind = np.where( yorgl[0] == 3 ) ; ddwind[ind] = np.NaN #; ddwinddir[ind] = np.NaN ; ddwinderror[ind] = np.NaN 52 | print "4. doubtful", yorgl[0][ind] 53 | 54 | #exit() 55 | 56 | ## constant_heights 57 | #for heights in [20.,100.,500.,1000.,2000.,5000.,7000.,10000.,20000.]: 58 | #for heights in [10.]: 59 | 60 | ## multiple_obsheight 61 | #for heights in [0.1,0.2,0.5,0.75,1.0,1.5,2.0,10.]: 62 | for heights in [1.0]: 63 | 64 | query = mcd() 65 | mcdwind = [] ; mcdwindle = [] ; mcdwindhe = [] ; mcdangle = [] ; mcdanglele = [] ; mcdanglehe = [] 66 | 67 | for i in yorgl[0]: 68 | 69 | if not isnan(ddwind[i-1]): 70 | query.lat = yorgl[1][i-1] 71 | query.lon = yorgl[2][i-1] 72 | query.xdate = yorgl[3][i-1] 73 | query.loct = yorgl[4][i-1] 74 | 75 | query.xz = ddheight[i-1] #ddheight is really the one that works best 76 | 77 | ## constant_heights 78 | #query.xz = heights 79 | ## multiple_obsheight 80 | query.xz = ddheight[i-1]*heights 81 | 82 | query.update() ; uu = query.zonwind ; vv = query.merwind 83 | if uu == -999. or vv == -999.: 84 | speed = np.NaN ; speedmin = np.NaN ; speedmax = np.NaN 85 | angle = np.NaN ; anglemin = np.NaN ; anglemax = np.NaN 86 | else: 87 | speed = np.sqrt(uu*uu+vv*vv) ; speedmin = speed ; speedmax = speed 88 | 89 | angle = 90. - np.arctan2(vv,uu) * 180. / np.pi 90 | if angle < 0.: angle = angle + 360. 91 | 92 | ## multiple_obsheight 93 | query.xzs = max(ddheight[i-1] - 2.*ddheighterror[i-1],10.) 94 | query.xze = ddheight[i-1] + 2.*ddheighterror[i-1] 95 | ## constant_heights 96 | #query.xzs = max(query.xz - 0.1*query.xz,10.) 97 | #query.xze = query.xz + 0.1*query.xz 98 | 99 | query.profile() 100 | tab = np.sqrt(query.zonwindtab*query.zonwindtab + query.merwindtab*query.merwindtab) 101 | tab2 = 90. - np.arctan2(query.merwindtab,query.zonwindtab) * 180. / np.pi 102 | tab2[np.where(tab2 < 0.)] = tab2[np.where(tab2 < 0.)] + 360. 103 | speedmin = min(tab) 104 | speedmax = max(tab) 105 | anglemin = min(tab2)-5. 106 | anglemax = max(tab2)+5. 107 | if anglemin < 0.: anglemin = angle - (anglemax - angle) 108 | print int(i), speed, speedmin, speedmax 109 | print int(i), angle, anglemin, anglemax 110 | else: 111 | #print "removed ",i,ddwinderror[i-1],ddheighterror[i-1] 112 | speed = -999. ; speedmin = -1000. ; speedmax = -998. ; angle = -999. ; anglemin = -1000. ; anglemax = -998. 113 | 114 | mcdwind.append(speed) 115 | mcdwindle.append(speed-speedmin) 116 | mcdwindhe.append(speedmax-speed) 117 | mcdangle.append(angle) 118 | mcdanglele.append(angle-anglemin) 119 | mcdanglehe.append(anglemax-angle) 120 | 121 | mcdwind = np.array(mcdwind) 122 | mcdwindle = np.array(mcdwindle) 123 | mcdwindhe = np.array(mcdwindhe) 124 | 125 | mcdangle = np.array(mcdangle) 126 | mcdanglele = np.array(mcdanglele) 127 | mcdanglehe = np.array(mcdanglehe) 128 | 129 | 130 | mpl.figure(figsize=(12,10)) 131 | mpl.plot([0,30], [stddev,stddev+30], 'g--') 132 | mpl.plot([0,30], [-stddev,-stddev+30], 'g--') 133 | mpl.plot([0,30], [0,30], 'g-') 134 | 135 | writeascii(field=mcdwind,absc=ddwind,name=str(heights)+'.txt') 136 | 137 | #ind = np.isnan(ddwind) 138 | #y = ddwind 139 | #y[ind] = -9999. 140 | #xi = mcdwind[y > -9999.] 141 | #y = ddwind[y > -9999.] 142 | #slope, intercept, r_value, p_value, std_err = stats.linregress(xi,y) 143 | #linear = slope*xi+intercept 144 | #mpl.plot(xi,linear) 145 | #ecart = y - linear 146 | #print np.std(ecart) 147 | 148 | mpl.errorbar(mcdwind, ddwind, yerr=[ddwinderror,ddwinderror], xerr=[mcdwindle,mcdwindhe], fmt='bo') 149 | # mpl.xlim(xmin=0.,xmax=17.) 150 | # mpl.ylim(ymin=0.,ymax=30.) 151 | mpl.xlim(xmin=0.,xmax=30.) 152 | mpl.ylim(ymin=0.,ymax=30.) 153 | 154 | 155 | mpl.xlabel('MCD horizontal wind speed (m/s)') 156 | mpl.ylabel('Dust devil observed drift speed (m/s)') 157 | 158 | 159 | for i in yorgl[0]: 160 | ## on multiplie stddev par 1.2 de facon a enlever les points tres au bord 161 | ## qui sont in si on considere l error bar 162 | if abs(ddwind[i-1] - mcdwind[i-1]) > stddev*1.2: 163 | mpl.annotate(str(int(i)), xy=(mcdwind[i-1], ddwind[i-1]), xytext=(10,2), 164 | textcoords='offset points', ha='center', va='bottom' )#, 165 | #bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3), 166 | #arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.3', 167 | #color='red')) 168 | 169 | 170 | #mpl.show() 171 | mpl.savefig("speed"+str(heights)+".eps") 172 | mpl.savefig("speed"+str(heights)+".png") 173 | ##mpl.savefig("comp4.eps") 174 | ##mpl.savefig("comp4.png") 175 | 176 | ddwinddirerror = mcdanglele*0. + 15. 177 | 178 | mpl.figure(figsize=(12,10)) 179 | mpl.errorbar(mcdangle,ddwinddir,yerr=[ddwinddirerror,ddwinddirerror],xerr=[mcdanglele,mcdanglehe],fmt='bo') 180 | mpl.plot(mcdangle,ddwinddir,'bo') 181 | mpl.xlim(xmin=0.,xmax=360.) 182 | mpl.ylim(ymin=0.,ymax=360.) 183 | 184 | mpl.xlabel('MCD horizontal wind orientation (deg)') 185 | mpl.ylabel('Dust devil observed drift orientation (deg)') 186 | 187 | 188 | stddev2 = 50. ## voir e.g. 8 9 10 189 | mpl.plot([0,360], [stddev2,stddev2+360], 'g--') 190 | mpl.plot([0,360], [-stddev2,-stddev2+360], 'g--') 191 | mpl.plot([0,360], [0,360], 'g-') 192 | 193 | 194 | for i in yorgl[0]: 195 | ## on multiplie stddev par 1.2 de facon a enlever les points tres au bord 196 | ## qui sont in si on considere l error bar 197 | if abs(ddwinddir[i-1] - mcdangle[i-1]) > stddev2*1.2: 198 | mpl.annotate(str(int(i)), xy=(mcdangle[i-1], ddwinddir[i-1]), xytext=(10,2), 199 | textcoords='offset points', ha='center', va='bottom')#, 200 | #bbox=dict(boxstyle='round,pad=0.2', fc='yellow', alpha=0.3), 201 | #arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=-0.3', 202 | #color='red')) 203 | 204 | ##xytext=(18,30) 205 | 206 | #mpl.show() 207 | mpl.savefig("angle"+str(heights)+".eps") 208 | mpl.savefig("angle"+str(heights)+".png") 209 | #mpl.savefig("comp3.eps") 210 | #mpl.savefig("comp3.png") 211 | 212 | #exit() 213 | # 214 | # 215 | #dd = mcd() 216 | # 217 | # 218 | # 219 | # 220 | # 221 | ##dd.zkey = 4 222 | ##dd.xzs = 600. 223 | ##dd.xze = 0.1 224 | ##dd.profile() 225 | ##dd.plot1d(["t","p"]) 226 | ##mpl.show() 227 | ##exit() 228 | # 229 | ### CASE 1 230 | #dd.lat = -14.6584 231 | #dd.lon = 175.54 232 | #dd.xdate = 265.278792 233 | #dd.loct = 14.8487 234 | #dd.xz = 130.4 235 | # 236 | #dd.update() 237 | #dd.printmcd() 238 | # 239 | #dd.lats = -5. 240 | #dd.late = -25. 241 | #dd.lons = 160. 242 | #dd.lone = 190. 243 | #dd.map2d(["wind"],incwind=True,fixedlt=True) 244 | ### il y a un piege pour les cartes locales il faut fixedlt=True 245 | #mpl.savefig("case1.png",dpi=110,bbox_inches='tight',pad_inches=0.4) 246 | # 247 | ### CASE 2 248 | #dd.lat = -68.6125 249 | #dd.lon = 11.4303 250 | #dd.xdate = 286.507293 251 | #dd.loct = 15.129030 252 | #dd.xz = 872.8 253 | ##dd.xz = 10000.0 254 | # 255 | #dd.update() 256 | #dd.printmcd() 257 | # 258 | #dd.lats = -75. 259 | #dd.late = -60. 260 | #dd.lons = 0. 261 | #dd.lone = 20. 262 | #dd.map2d(["wind"],incwind=True,fixedlt=True) 263 | #mpl.savefig("case2.png",dpi=110,bbox_inches='tight',pad_inches=0.4) 264 | # 265 | ###3 25,1306 314,4842 60,8946 14,9971 30,89575722 232 250,217961736111 266 | # 267 | ### CASE 3 268 | #dd.lat = 25.1306 269 | #dd.lon = 314.4842 270 | #dd.xdate = 60.8946 271 | #dd.loct = 14.9971 272 | #dd.xz = 250.218 273 | # 274 | #dd.update() 275 | #dd.printmcd() 276 | # 277 | ###4 35,564 199,486 60,5883 14,9949 12,2972688101353 125 895,247012611329 278 | # 279 | ### CASE 4 280 | #dd.lat = 35.564 281 | #dd.lon = 199.486 282 | #dd.xdate = 60.5883 283 | #dd.loct = 14.9949 284 | #dd.xz = 895.247 285 | # 286 | #dd.update() 287 | #dd.printmcd() 288 | # 289 | ###5 68,346 234,396 142,828 15,1777 13,4079899322222 83 1128,06581216829 290 | ###6 68,316 234,462 142,828 15,1819 16,1939071396022 85 582,624074786015 291 | ###7 68,302 234,144 142,828 15,1607 17,3354121022885 112 262,299040101764 292 | # 293 | ### CASE 5 294 | #dd.lat = 68.32 295 | #dd.lon = 234.3 296 | #dd.xdate = 142.828 297 | #dd.loct = 15.2 298 | # 299 | #dd.xz = 1128.066 300 | #dd.update() 301 | #dd.printmcd() 302 | # 303 | #dd.xz = 582.624 304 | #dd.update() 305 | #dd.printmcd() 306 | # 307 | #dd.xz = 262.299 308 | #dd.update() 309 | #dd.printmcd() 310 | # 311 | # 312 | ###19 27,055 129,614 13,5818 14,444 42,6488205391137 302 1395,96076100437 313 | # 314 | ### CASE 19 315 | #dd.lat = 27.055 316 | #dd.lon = 129.614 317 | #dd.xdate = 13.5818 318 | #dd.loct = 14.444 319 | # 320 | #dd.xz = 1395.961 321 | #dd.update() 322 | #dd.printmcd() 323 | # 324 | #dd.lats = 20. 325 | #dd.late = 30. 326 | #dd.lons = 125. 327 | #dd.lone = 135. 328 | #dd.map2d(["wind"],incwind=True,fixedlt=True) 329 | #mpl.savefig("case19.png",dpi=110,bbox_inches='tight',pad_inches=0.4) 330 | # 331 | # 332 | -------------------------------------------------------------------------------- /perso/gw.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | import numpy as np # numerics 3 | from mcd import mcd # MCD python wrapper 4 | import ppplot # for plots 5 | import ppcompute # for derivatives 6 | import planets # for N2 computation 7 | 8 | ############################## 9 | # this script computes # 10 | # GW saturation ratio # 11 | # from MCD field # 12 | # see Spiga et al. GRL 2012 # 13 | ############################## 14 | Ls = 30. 15 | Ls = 90. 16 | Ls = 270. 17 | ############## 18 | 19 | # the constant in the saturation ratio 20 | # ... see Spiga et al. GRL 2012 21 | lambdah = 150e3 22 | fzero = 7.5e-7 23 | alpha = fzero*lambdah/(2.*np.pi) 24 | 25 | # prepare MCD request 26 | rq = mcd() 27 | rq.xdate = Ls 28 | # xzs should not be 0 otherwise divide by u=0 29 | rq.xzs,rq.xze = 40000.,180000. 30 | 31 | # request zonal mean 32 | #rq.zonalmean() 33 | rq.lon = 0. ; rq.secalt() 34 | 35 | # coordinates 36 | z = rq.ycoord 37 | lat = rq.xcoord 38 | # zonal wind 39 | u = np.transpose(rq.zonwindtab) 40 | # density 41 | rho = np.transpose(rq.denstab) 42 | # static stability 43 | temp = np.transpose(rq.temptab) 44 | dummy,dTdz = ppcompute.deriv2d(temp,lat,z) 45 | bv = planets.Mars.N2(T0=temp,dTdz=dTdz) 46 | 47 | # compute saturation ratio 48 | s = np.sqrt(alpha*bv/(rho*np.abs(u)*u*u)) 49 | w = np.where(s>1) ; s[w] = 1. # S ratio is <= 1 50 | 51 | # plot bounds -- same as Spiga et al. 2012 52 | lb,ub = -2.,-0.5 53 | w = np.where(np.log10(s)ub) ; s[w] = 10.**(ub) 55 | 56 | # plot 57 | pl = ppplot.plot2d() 58 | pl.f = np.log10(s) 59 | pl.x = lat ; pl.xlabel = "Latitude" 60 | pl.y = z/1000. ; pl.ylabel = "Altitude (km)" 61 | pl.c = u 62 | pl.colorbar = "hot_r" 63 | pl.fmt = "%.1f" 64 | pl.units = r'$\log_{10}\mathcal{S}$' 65 | pl.makesave(mode="png",filename="saturatio_%.0f" % (Ls)) 66 | -------------------------------------------------------------------------------- /perso/inimeso/from_gcm.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from string import split 3 | import numpy as np 4 | from ppclass import pp 5 | import ppplot 6 | 7 | 8 | shiftday = 258 + 27 9 | shiftday = 258 10 | 11 | ### GET COORDINATES 12 | lines = open("input_coord", "r").readlines() 13 | lon = float(split(lines[0])[0]) ; lat = float(split(lines[1])[0]) 14 | xdate = float(split(lines[2])[0]) ; loct = float(split(lines[3])[0]) 15 | utc = loct - lon/15. 16 | 17 | ### GCM 18 | req = pp() 19 | req.file = "diagfi.nc" 20 | req.var = "vmr_h2ovap" 21 | req.var = "temp" 22 | req.x = lon 23 | req.y = lat 24 | req.t = shiftday + utc/24. 25 | req.verbose = True 26 | req.changetime = "mars_dayini" 27 | #prof,xx,yy,zz,tt = req.getfd() 28 | 29 | ### MCD 30 | z,tpot,q,u,v = np.loadtxt("input_sounding",skiprows=1,unpack=True) 31 | r,cp,p,rho,t = np.loadtxt("input_therm",unpack=True) 32 | hgt,tsurf = np.loadtxt("input_more",unpack=True) 33 | q = 0.001*q 34 | 35 | ### PLOT 36 | 37 | nnn=60 38 | dd=10 39 | ppplot.rainbow(cb="jet",num=1+(nnn/dd)) 40 | 41 | sdg = ppplot.plot1d() 42 | sdg.f = z-hgt 43 | sdg.x = q 44 | sdg.x = t 45 | sdg.legend = 'mcd' 46 | sdg.marker = 's' 47 | sdg.color = 'w' 48 | sdg.make() 49 | 50 | 51 | nnn=60 52 | dd=10 53 | ppplot.rainbow(cb="jet",num=nnn/dd) 54 | 55 | ppp = ppplot.plot1d() 56 | ppp.marker = '.' 57 | ppp.ymax = 9000. 58 | ppp.xlabel = 'temperature (K)' 59 | ppp.ylabel = 'altitude (m)' 60 | 61 | for iii in range(0,nnn,dd): 62 | if iii == 0: 63 | sdg.verbose = True 64 | req.t = 258 + iii + utc/24. 65 | prof,xx,yy,zz,tt = req.getfd() 66 | ppp.x = prof 67 | ppp.f = zz*1000. 68 | ppp.legend = 'gcm sol 258+'+str(iii) 69 | ppp.make() 70 | 71 | ppplot.save(mode="png",filename="comp") 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /perso/inimeso/inimeso.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | ### AS 10/05/2012. A python script to prepare initial state for idealized mesoscale runs. 4 | ### use : ensure mcd class is working. fill in input_coord. execute inimeso. 5 | 6 | from string import split ; import numpy as np ; import matplotlib.pyplot as mpl 7 | from mcd import mcd 8 | 9 | ### MCD INSTANCE and SETTINGS (actually, default. but one never knows) 10 | query = mcd() ; query.zkey = 3 ; query.hrkey = 1 11 | query.dust = 2 #29 12 | 13 | ### GET COORDINATES 14 | lines = open("input_coord", "r").readlines() 15 | query.lon = float(split(lines[0])[0]) ; query.lat = float(split(lines[1])[0]) 16 | query.xdate = float(split(lines[2])[0]) ; query.loct = float(split(lines[3])[0]) 17 | query.printcoord() 18 | 19 | ### OPEN FILES TO BE WRITTEN 20 | sounding = open("input_sounding", "w") ; additional = open("input_therm", "w") ; more = open("input_more", "w") 21 | 22 | ### GET and WRITE SURFACE VALUES 23 | query.xz = 0. ; query.update() ; query.printmeanvar() 24 | sounding.write( "%10.2f%12.2f%12.2f\n" % (query.pres/100.,query.temp*(610./query.pres)**(1.0/3.9),0.) ) 25 | more.write( "%10.2f%10.2f" % (query.extvar[1],query.extvar[14]) ) ; more.close() 26 | 27 | ### GET and WRITE VERTICAL PROFILE 28 | query.profile( tabperso = np.append([0,1,5,10,20,50,100],np.linspace(200.,float(split(lines[4])[0])*1000.,float(split(lines[5])[0]))) ) 29 | for iz in range(len(query.prestab)): 30 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % ( \ 31 | query.extvartab[iz,2],query.temptab[iz]*(610./query.prestab[iz])**(1.0/3.9),\ 32 | 0.,query.zonwindtab[iz],query.merwindtab[iz]) ) 33 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % ( \ 34 | query.extvartab[iz,49],query.extvartab[iz,8],\ 35 | query.prestab[iz],query.denstab[iz],query.temptab[iz]) ) 36 | 37 | ### FINISH 38 | sounding.close() ; additional.close() 39 | query.plot1d(["p","t","u","v"]) ; mpl.show() 40 | 41 | ### Add information about dust opacity 42 | dod = open("dustopacity.def", "w") 43 | dod.write( "%4.2f" %(query.extvartab[iz,36]) ) 44 | dod.close() 45 | -------------------------------------------------------------------------------- /perso/inimeso/inimeso5.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | ### AS 10/05/2012. A python script to prepare initial state for idealized mesoscale runs. 4 | ### use : ensure mcd class is working. fill in input_coord. execute inimeso. 5 | 6 | from string import split ; import numpy as np ; import matplotlib.pyplot as mpl 7 | from mcd import mcd 8 | 9 | rho_dust = 2500. # Mars dust density (kg.m-3) 10 | grav = 3.72 11 | ksi = 3. / 4. / rho_dust / grav 12 | nueff = 0.5 13 | 14 | ### MCD INSTANCE and SETTINGS (actually, default. but one never knows) 15 | query = mcd() ; query.zkey = 3 ; query.hrkey = 1 16 | #query.toversion5(version="5.2") 17 | 18 | ### GET COORDINATES 19 | lines = open("input_coord", "r").readlines() 20 | query.lon = float(split(lines[0])[0]) ; query.lat = float(split(lines[1])[0]) 21 | query.xdate = float(split(lines[2])[0]) ; query.loct = float(split(lines[3])[0]) 22 | query.dust = float(split(lines[6])[0]) 23 | query.printcoord() 24 | 25 | ### OPEN FILES TO BE WRITTEN 26 | sounding = open("input_sounding", "w") ; additional = open("input_therm", "w") ; more = open("input_more", "w") 27 | dust = open("input_dust", "w") ; water = open("input_water", "w") 28 | 29 | ### GET and WRITE SURFACE VALUES 30 | query.xz = 0.1 ; query.update() ; query.printmeanvar() 31 | wvapor = query.extvar[42] #1.5*1e-3 32 | wice = query.extvar[44] #0.0 33 | sounding.write( "%10.2f%12.2f%12.2f\n" % (query.pres/100.,query.temp*(610./query.pres)**(1.0/3.9),(wvapor+wice)*1e3) ) 34 | more.write( "%10.2f%10.2f" % (query.extvar[1],query.extvar[14]) ) ; more.close() 35 | 36 | ### GET and WRITE VERTICAL PROFILE 37 | #closesurf = [0.1,5,10,20,50,100] 38 | closesurf = [0.1,0.5,1,2,5,10,20,50,100] 39 | query.profile( tabperso = np.append(closesurf,np.linspace(200.,float(split(lines[4])[0])*1000.,float(split(lines[5])[0]))) ) 40 | for iz in range(len(query.prestab)): 41 | 42 | wvapor = query.extvartab[iz,42] #1.5*1e-3 43 | wice = query.extvartab[iz,44] #0.0 44 | 45 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % ( \ 46 | query.extvartab[iz,2],query.temptab[iz]*(610./query.prestab[iz])**(1.0/3.9),\ 47 | (wvapor+wice)*1e3,\ 48 | query.zonwindtab[iz],query.merwindtab[iz]) ) 49 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % ( \ 50 | query.extvartab[iz,53],query.extvartab[iz,8],\ 51 | query.prestab[iz],query.denstab[iz],query.temptab[iz]) ) 52 | water.write( "%18.6e%18.6e\n" % (wvapor*1e3,wice*1e3) ) 53 | 54 | ### DUST PROFILES 55 | q = query.extvartab[iz,38] # extvar(38)= Dust mass mixing ratio (kg/kg) 56 | reff = query.extvartab[iz,39] # extvar(39)= Dust effective radius (m) 57 | print q,reff 58 | N = (grav*ksi*((1+nueff)**3)/np.pi)*q/(reff**3) 59 | dust.write( "%18.6e%18.6e\n" % (q,N) ) 60 | 61 | ### FINISH 62 | sounding.close() ; additional.close() ; dust.close() ; water.close() 63 | query.plot1d(["p","t","u","v","h2ovap","h2oice"]) ; mpl.show() 64 | 65 | 66 | 67 | 68 | 69 | 70 | ##### ESTIMATE CCNs 71 | #dustq,dustn = np.loadtxt("input_dust",unpack=True) 72 | ############################################################################# 73 | ############################################################################# 74 | ##fqdust = np.squeeze(query.extvartab[:,38]) 75 | #fwice = np.squeeze(query.extvartab[:,44]) 76 | ##### 77 | ##### I: fwice, fqdust --> O: finter 78 | ##### 79 | ##import numpy as np 80 | #from scipy.interpolate import InterpolatedUnivariateSpline 81 | ### remove profile points with a cloud 82 | #x = np.arange(fwice.size) 83 | #w = np.where(fwice < np.mean(fwice)/10.) 84 | ### spline-interpolate with remaining points 85 | #yyq = dustq[w] 86 | #xxq = x[w] 87 | #splq = InterpolatedUnivariateSpline(xxq, yyq) 88 | #yyn = dustn[w] 89 | #xxn = x[w] 90 | #spln = InterpolatedUnivariateSpline(xxn, yyn) 91 | ### get interpolated profile 92 | ### -- a good match for qdust + qccn 93 | ### -- treat negative values because of spline 94 | #finterq = splq(x) - dustq 95 | #finterq[np.where(finterq < 0.)] = -finterq[np.where(finterq < 0.)] 96 | #fintern = spln(x) - dustn 97 | #fintern[np.where(fintern < 0.)] = -fintern[np.where(fintern < 0.)] 98 | ### plot 99 | #mpl.figure() 100 | #mpl.plot(yyn,xxn,'bo') 101 | #mpl.plot(dustn,x) 102 | #mpl.plot(fintern,x) 103 | #mpl.figure() 104 | #mpl.plot(yyq,xxq,'bo') 105 | #mpl.plot(dustq,x) 106 | #mpl.plot(finterq,x) 107 | #mpl.figure() 108 | #mpl.plot(fwice,x,'b.') 109 | #mpl.show() 110 | ############################################################################# 111 | ############################################################################# 112 | # 113 | #ccn = open("input_ccn", "w") 114 | #for iz in range(len(query.prestab)): 115 | # print iz,dustq[iz],finterq[iz] 116 | # #ccn.write( "%18.6e%18.6e\n" % (finterq[iz],fintern[iz]) ) 117 | # ccn.write( "%18.6e%18.6e\n" % (np.max(finterq),np.max(fintern)) ) 118 | #ccn.close() 119 | -------------------------------------------------------------------------------- /perso/inimeso/input_coord: -------------------------------------------------------------------------------- 1 | -125.75 lon 2 | 68.22 lat 3 | 122. ls 4 | 23. lct 5 | 25 ztop 6 | 100. nz 7 | 8 dust_scenario 8 | 9 | c 1 = Climatology ave solar 10 | c 2 = Climatology min solar 11 | c 3 = Climatology max solar 12 | c 4 = dust storm tau=5 (dark dust) min solar 13 | c 5 = dust storm tau=5 (dark dust) ave solar 14 | c 6 = dust storm tau=5 (dark dust) max solar 15 | c 7 = warm scenario - dusty, max solar 16 | c 8 = cold scenario - low dust, min solar 17 | c 24 = Mars Year 24, with associated solar EUV 18 | c 25 = Mars Year 25, with associated solar EUV 19 | c 26 = Mars Year 26, with associated solar EUV 20 | c 27 = Mars Year 27, with associated solar EUV 21 | c 28 = Mars Year 28, with associated solar EUV 22 | c 29 = Mars Year 29, with associated solar EUV 23 | c 30 = Mars Year 30, with associated solar EUV 24 | c 31 = Mars Year 31, with associated solar EUV 25 | 26 | 27 | 136.0 lon 28 | 4.4 lat 29 | 295.0 ls 30 | 7. lct 31 | 20 ztop 32 | 100. nz 33 | 34 | 326.0 lon 35 | -26.1 lat 36 | 348. ls 37 | 08. lct 38 | 20. ztop 39 | 100. nz 40 | 41 | 42 | -195.5 lon 43 | 73. lat 44 | 90.0 ls 45 | 08. lct 46 | 60. ztop 47 | 100. nz 48 | 49 | 204.6 lon 50 | 13.7 lat 51 | 140.0 ls 52 | 08. lct 53 | 20. ztop 54 | 100. nz 55 | 56 | 04.6 lon 57 | 13.7 lat 58 | 140.0 ls 59 | 08. lct 60 | 20. ztop 61 | 100. nz 62 | 63 | -195.5 lon 64 | 73. lat 65 | 90.0 ls 66 | 08. lct 67 | 20. ztop 68 | 100. nz 69 | 70 | 353.87 lon 71 | -1.88 lat 72 | 244. ls 73 | 06. lct 74 | 20 ztop 75 | 100. nz 76 | -------------------------------------------------------------------------------- /perso/inimeso/profile.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # get a multicolumn file with profiles of z,P,T,rho 4 | 5 | from string import split 6 | import numpy as np 7 | import matplotlib.pyplot as mpl 8 | from mcd import mcd 9 | 10 | ### MCD INSTANCE and SETTINGS (actually, default. but one never knows) 11 | query = mcd() ; query.zkey = 3 ; query.dust = 2 ; query.hrkey = 1 12 | query.dust = 29 13 | #query.dust = 24 14 | query.toversion5(version="5.2") 15 | 16 | ### GET COORDINATES 17 | lines = open("input_coord", "r").readlines() 18 | query.lon = float(split(lines[0])[0]) 19 | query.lat = float(split(lines[1])[0]) 20 | query.xdate = float(split(lines[2])[0]) 21 | query.loct = float(split(lines[3])[0]) 22 | query.printcoord() 23 | 24 | ### OPEN FILES TO BE WRITTEN 25 | zefile = open("profile.txt", "w") 26 | 27 | ### HEADER 28 | query.gettitle() 29 | zefile.write(query.ack + "\n") 30 | zefile.write(query.title+"\n") 31 | zefile.write("------------------------------\n") 32 | zefile.write("altitude (m) // pressure (Pa) // density (kg/m3) // temperature (K)\n") 33 | zefile.write("------------------------------\n") 34 | 35 | ### GET AND WRITE PROFILE 36 | query.profile( tabperso = np.append([0.1,5,10,20,50,100],np.linspace(200.,float(split(lines[4])[0])*1000.,float(split(lines[5])[0]))) ) 37 | 38 | 39 | for iz in range(len(query.prestab)): 40 | zefile.write( "%15.4e%15.4e%15.4e%15.4e\n" % ( \ 41 | query.xcoord[iz],query.prestab[iz],query.denstab[iz],query.temptab[iz]) ) 42 | 43 | ### FINISH 44 | zefile.close() 45 | query.plot1d(["p","t","rho"]) ; mpl.show() 46 | 47 | -------------------------------------------------------------------------------- /perso/inimeso/shift_temp.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | import numpy as np 3 | 4 | shift = -10. 5 | 6 | # load data 7 | # http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html 8 | yy,yyy = np.loadtxt("input_more",unpack=True) 9 | gg,ggg,gggg = np.loadtxt("input_sounding",unpack=True) 10 | z,tpot,q,u,v = np.loadtxt("input_sounding",skiprows=1,unpack=True) 11 | r,cp,p,rho,t = np.loadtxt("input_therm",unpack=True) 12 | 13 | 14 | tpot_save = tpot 15 | t = t + shift 16 | tpot = t*(610./p)**(1.0/3.9) 17 | 18 | print "------------------------------------" 19 | print "shifts in potential temperature are:" 20 | print tpot-tpot_save 21 | 22 | more = open("input_more", "w") 23 | more.write( "%10.2f%10.2f" % (yy,t[0]) ) 24 | more.close() 25 | sounding = open("input_sounding", "w") 26 | additional = open("input_therm", "w") 27 | sounding.write( "%10.2f%12.2f%12.2f\n" % (gg[0],tpot[0],gggg[0]) ) 28 | for iz in range(len(p)): 29 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % (z[iz],tpot[iz],q[iz],u[iz],v[iz]) ) 30 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % ( r[iz],cp[iz],p[iz],rho[iz],t[iz] ) ) 31 | sounding.close() 32 | additional.close() 33 | -------------------------------------------------------------------------------- /perso/inimeso/venus/getvenus.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from string import split 3 | import numpy as np 4 | from ppclass import pp 5 | import ppplot 6 | from planets import Venus 7 | 8 | ############################ 9 | zefile = "yorgl.nc" 10 | ttt = 1 11 | ############################ 12 | 13 | ### GET COORDINATES 14 | lines = open("input_coord", "r").readlines() 15 | lon = float(split(lines[0])[0]) ; lat = float(split(lines[1])[0]) 16 | xdate = float(split(lines[2])[0]) ; loct = float(split(lines[3])[0]) 17 | 18 | ### GCM 19 | temp = pp(file=zefile,t=ttt,x=lon,y=lat,var="temp" ).getf() 20 | pres = pp(file=zefile,t=ttt,x=lon,y=lat,var="pres" ).getf() 21 | vitu = pp(file=zefile,t=ttt,x=lon,y=lat,var="vitu" ).getf() 22 | vitv = pp(file=zefile,t=ttt,x=lon,y=lat,var="vitv" ).getf() 23 | dtlwr = pp(file=zefile,t=ttt,x=lon,y=lat,var="dtlwr").getf() 24 | dtswr = pp(file=zefile,t=ttt,x=lon,y=lat,var="dtswr").getf() 25 | geop = pp(file=zefile,t=ttt,x=lon,y=lat,var="geop").getf() 26 | 27 | ### COMPUTATIONS 28 | refpres = pres[0] ; surftpot = temp[0] ; surfh = 0. 29 | ### -- tpot 30 | tpot = temp*(refpres/pres)**(Venus.R()/Venus.cp) 31 | ### -- alt 32 | #alt = Venus.H(T0=temp)*np.log(refpres/pres) 33 | alt = geop / Venus.g 34 | ### -- rho 35 | rho = pres / Venus.R() / temp 36 | 37 | ### CHECK WITH A PLOT 38 | pl = ppplot.plot1d(f=alt,x=tpot).makeshow() 39 | pl = ppplot.plot1d(f=alt,x=rho).makeshow() 40 | pl = ppplot.plot1d(f=alt,x=temp).makeshow() 41 | 42 | ### OPEN FILES TO BE WRITTEN 43 | sounding = open("input_sounding", "w") 44 | additional = open("input_therm", "w") 45 | more = open("input_more", "w") 46 | hr = open("input_hr", "w") 47 | 48 | ### GET and WRITE SURFACE VALUES 49 | sounding.write( "%10.2f%12.2f%12.2f\n" % (refpres/100.,surftpot,0.) ) 50 | more.write( "%10.2f%10.2f" % (surfh,surftpot) ) 51 | 52 | ### GET and WRITE VERTICAL PROFILE 53 | nz = len(pres) 54 | for iz in range(nz): 55 | sounding.write( "%10.2f%12.2f%12.2f%12.2f%12.2f\n" % (alt[iz],tpot[iz],0.,vitu[iz],vitv[iz]) ) 56 | additional.write( "%12.2f%12.2f%18.6e%18.6e%12.2f\n" % (Venus.R(),Venus.cp,pres[iz],rho[iz],temp[iz]) ) 57 | hr.write( "%18.6e%18.6e\n" % (dtswr[iz],dtlwr[iz]) ) 58 | 59 | ### CLOSE FILES 60 | sounding.close() 61 | additional.close() 62 | more.close() 63 | hr.close() 64 | -------------------------------------------------------------------------------- /perso/inimeso/venus/input_coord: -------------------------------------------------------------------------------- 1 | 180.0 lon 2 | 30.0 lat 3 | 0.0 ls 4 | 00. lct 5 | 999. ztop 6 | 999. nz 7 | 8 | -------------------------------------------------------------------------------- /perso/phoenix.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | from mcd import mcd 3 | import numpy as np 4 | 5 | ##122 127 6 | 7 | ph = mcd() 8 | 9 | ph.lat = 68.22 10 | ph.lon = 234.25 11 | ph.xdate = 122. 12 | ph.xz = 5000. 13 | ph.loct = 3. 14 | ph.zkey = 3 15 | 16 | yy = [] 17 | for iii in np.arange(-50,50,1): 18 | ph.perturkey = 4 # large-scale + small-scale 19 | ph.seedin = iii #random number generator seed (unused if perturkey=0) 20 | ph.update() 21 | yy.append(ph.temp) 22 | 23 | print np.mean(yy) 24 | print np.std(yy) 25 | -------------------------------------------------------------------------------- /quicktest.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from mcd import mcd_class 4 | req = mcd_class() 5 | req.lat = -4.6 6 | req.lon = 137.4 7 | req.loct = 15 8 | req.xz = 1 9 | req.xdate = 150.6 10 | req.update() 11 | req.printmeanvar() 12 | 13 | -------------------------------------------------------------------------------- /test_mcd/MCD_DATA: -------------------------------------------------------------------------------- 1 | ../../../MCD_v5.2/data -------------------------------------------------------------------------------- /test_mcd/README: -------------------------------------------------------------------------------- 1 | ### TEST_MCD: a simple example of requesting fields from the MCD 2 | 3 | CONTENTS: 4 | ========= 5 | test_mcd.py Example of a python script calling the mcd 6 | test_mcd.def Example of user inputs to test_mcd.py 7 | 8 | GENERAL DESCRIPTION: 9 | ==================== 10 | The test_mcd.py python script is an illustrative example of how one may 11 | call upon the fortran routine call_mcd.F (as well as the Julian.F routine) 12 | to retreive data from the Mars Climate Database. 13 | 14 | USAGE: 15 | ====== 16 | The "test_mcd.py" script provides a simple and straightforward example of 17 | how one can call the mcd from within a python script. When run it requires 18 | some input from the user (hence the "test_mcd.def" file, for those who prefer 19 | to redirect input from a file rather than type as the program proceeds). 20 | 21 | WARNING: 22 | ======== 23 | Either set the link MCD_DATA in this folder 24 | Or change the dset variable in the scripts 25 | -------------------------------------------------------------------------------- /test_mcd/test_mcd.def: -------------------------------------------------------------------------------- 1 | m 2 | 315 3 | 0.0 4 | 3 5 | 500 6 | 0 7 | 0. 8 | 0. 9 | 1 10 | 1 11 | 1 12 | 13 | 14 | This file can be use as an input to the example program test_mcd. Just type: 15 | 16 | test_mcd.py < test_mcd.def 17 | -------------------------------------------------------------------------------- /test_mcd/test_mcd.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # This python program illustrates how the Mars Climate Database 4 | # fortran routines can be called interactively from python 5 | 6 | from fmcd import call_mcd,julian 7 | import numpy as np 8 | 9 | # 1. Inputs: 10 | dset = '' # default to 'MCD_DATA' 11 | perturkey = 1 # default to no perturbation 12 | seedin = 0 # perturbation seed (unused if perturkey=1) 13 | gwlength = 0 # Gravity Wave length for perturbations (unused if perturkey=1) 14 | 15 | # 1.1 Dates 16 | choice_date=raw_input('Use Earth date (e) or Mars date (m)?') 17 | if (choice_date == "e") : 18 | datekey=0 # Earth date 19 | loct=0 # local time must then also be set to zero 20 | day,month,year,hour,minute,second = \ 21 | raw_input("Enter date: day/month/year/hour/minute/second: ").split('/') 22 | day=int(day) 23 | month=int(month) 24 | year=int(year) 25 | hour=int(hour) 26 | minute=int(minute) 27 | second=int(second) 28 | # now call Julian routine to convert to julian date 29 | (ier,xdate)=julian(month,day,year,hour,minute,second) 30 | print " Julian date %16.8f" % xdate 31 | else : 32 | datekey=1 # Mars date 33 | xdate=float(raw_input("Enter solar longitude Ls (deg.):")) 34 | loct=float(raw_input("Local time (0 < time < 24)?")) 35 | 36 | # 1.2 Vertical coordinate 37 | zkey=int(raw_input("Select verical coordinate type (1: distance to center of planet, 2: height above areoid, 3: height above surface, 4: Pressure) ")) 38 | if (zkey == 1) : 39 | xz=float(raw_input("Enter distance to planet center (m) ")) 40 | if (zkey == 2) : 41 | xz=float(raw_input("Enter altitude above areoid (m) ")) 42 | if (zkey == 3) : 43 | xz=float(raw_input("Enter altitude above surface (m) ")) 44 | if (zkey == 4) : 45 | xz=float(raw_input("Enter pressure value (Pa) ")) 46 | 47 | # high resolution mode 48 | hrkey=int(raw_input("High resolution? (1: yes, 0: no) ")) 49 | 50 | # 1.3 Position 51 | lat = float(raw_input('Latitude (deg)?')) 52 | lon = float(raw_input('Longitude (deg)?')) 53 | 54 | # 1.4 Dust and solar scenario 55 | print "Dust scenario?" 56 | print "1= Climatology typical Mars year dust scenario" 57 | print " average solar EUV conditions" 58 | print "2= Climatology typical Mars year dust scenario" 59 | print " minimum solar EUV conditions" 60 | print "3= Climatology typical Mars year dust scenario" 61 | print " maximum solar EUV conditions" 62 | print "4= dust storm constant dust opacity = 5 (dark dust)" 63 | print " minimum solar EUV conditions" 64 | print "5= dust storm constant dust opacity = 5 (dark dust)" 65 | print " average solar EUV conditions" 66 | print "6= dust storm constant dust opacity = 5 (dark dust)" 67 | print " maximum solar EUV conditions" 68 | print "7= warm scenario dustier than Climatology scenario" 69 | print " maximum solar EUV conditions" 70 | print "8= cold scenario clearer than Climatology scenario" 71 | print " minimum solar EUV conditions" 72 | dust=int(raw_input('')) 73 | 74 | # 1.5 perturbations 75 | perturkey=int(raw_input("Perturbation? (1:none, 2: large scale, 3: small scale, 4: small+large, 5: n sigmas) ")) 76 | if (perturkey > 1) : 77 | seedin=int(raw_input("seedin? (only matters if adding perturbations) ")) 78 | if ((perturkey == 3) or (perturkey == 4)) : 79 | gwlength=float(raw_input("Gravity wave length? (for small scale perturbations) ")) 80 | 81 | # 1.6 extra outputs 82 | # here we only implement an all-or-nothing case 83 | extvarkey=int(raw_input("Output the extra variables? (yes==1; no==0) ")) 84 | if (extvarkey == 0) : 85 | extvarkeys = np.zeros(100) 86 | else : 87 | extvarkeys = np.ones(100) 88 | 89 | # 2. Call MCD 90 | (pres, dens, temp, zonwind, merwind, \ 91 | meanvar, extvar, seedout, ierr) \ 92 | = \ 93 | call_mcd(zkey,xz,lon,lat,hrkey, \ 94 | datekey,xdate,loct,dset,dust, \ 95 | perturkey,seedin,gwlength,extvarkeys ) 96 | 97 | # 3. Write outputs 98 | print "temperature is %.0f K, pressure is %.0f Pa, density is %5.3e kg/m3, zonal wind is %.1f m/s, meridional wind is %.1f m/s" % (temp,pres,dens,zonwind,merwind) 99 | 100 | -------------------------------------------------------------------------------- /test_mcd/test_mcd_light.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from fmcd import call_mcd 4 | import numpy as np 5 | 6 | lon = float(raw_input('Longitude?')) 7 | lat = float(raw_input('Latitude?')) 8 | xdate = float(raw_input('Ls?')) 9 | loct = float(raw_input('Local time?')) 10 | xz = float(raw_input('Altitude?')) 11 | 12 | #dset = '/home/aymeric/Science/MCD_v4.3/data/' 13 | dset = './MCD_DATA/' 14 | 15 | zkey = 3 # specify that xz is the altitude above surface (m) 16 | datekey = 1 # 1 = "Mars date": xdate is the value of Ls 17 | dust = 2 #our best guess MY24 scenario, with solar average conditions 18 | hrkey = 1 #set high resolution mode on (hrkey=0 to set high resolution off) 19 | perturkey = 0 #integer perturkey ! perturbation type (0: none) 20 | seedin = 1 #random number generator seed (unused if perturkey=0) 21 | gwlength = 0. #gravity Wave wavelength (unused if perturkey=0) 22 | #extvarkey = 1 23 | #extvarkeys = np.ones(100) 24 | extvarkeys = np.zeros(100) 25 | 26 | (pres, dens, temp, zonwind, merwind, \ 27 | meanvar, extvar, seedout, ierr) \ 28 | = \ 29 | call_mcd(zkey,xz,lon,lat,hrkey, \ 30 | datekey,xdate,loct,dset,dust, \ 31 | perturkey,seedin,gwlength,extvarkeys ) 32 | 33 | print "temperature is %.0f K, pressure is %.0f Pa, density is %5.3e kg/m3, zonal wind is %.1f m/s, meridional wind is %.1f m/s" % (temp,pres,dens,zonwind,merwind) 34 | 35 | --------------------------------------------------------------------------------