diff --git a/_config.yml b/_config.yml index d6ce4e5..88ba749 100644 --- a/_config.yml +++ b/_config.yml @@ -7,7 +7,7 @@ # dc: Data Carpentry # lc: Library Carpentry # cp: Carpentries (to use for instructor traning for instance) -carpentry: "swc" +carpentry: "molssi" # Overall title for pages. title: "Python Scripting for Computational Molecular Science" diff --git a/_episodes/07-command_line.md b/_episodes/07-command_line.md index 2d95875..f605969 100644 --- a/_episodes/07-command_line.md +++ b/_episodes/07-command_line.md @@ -3,7 +3,8 @@ title: "Running code from the Linux Command Line" teaching: 15 exercises: 10 questions: -- "How do I move my code from the interactive jupyter notebook to run from the Linux command line?" +- "How do I move my code from the interactive Jupyter notebook to run from the Linux command line?" +- "How do I make Python scripts with help messages and user inputs using argparse?" objectives: - "Make code executable from the Linux command line." - "Use argparse to accept user inputs." diff --git a/_episodes/07-command_line_sys.md b/_episodes/07-command_line_sys.md new file mode 100644 index 0000000..c91d9bb --- /dev/null +++ b/_episodes/07-command_line_sys.md @@ -0,0 +1,171 @@ +--- +title: "Running code from the Linux Command Line" +teaching: 15 +exercises: 10 +alternate: true +questions: +- "How do I move my code from the interactive Jupyter notebook to run from the Linux command line?" +- "How do I make simple Python scripts with user inputs using sys.argv?" +objectives: +- "Make code executable from the Linux command line." +- "Use sys.argv() to accept user inputs." +keypoints: +- "You must `import sys` in your code to accept user arguments." +- "The name of the script itself is always `sys.argv[0]` so the first user input is normally `sys.argv[1]`." +--- +## Creating and running a python input file + +We are now going to move our geometry analysis code out of the Jupyter notebook and into a format that can be run from the Linux command line. Open your favorite text editor and create a new file called "geom_analysis.py" (or choose another filename, just make sure the extension is .py). Paste in your geometry analysis code (the version with your functions) from your jupyter notebook and save your file. + +The best practice is to put all your functions at the top of the file, right after your import statements. Your file will look something like this. +``` +import numpy +import os + +def calculate_distance(atom1_coord, atom2_coord): + x_distance = atom1_coord[0] - atom2_coord[0] + y_distance = atom1_coord[1] - atom2_coord[1] + z_distance = atom1_coord[2] - atom2_coord[2] + bond_length_12 = numpy.sqrt(x_distance**2+y_distance**2+z_distance**2) + return bond_length_12 + +def bond_check(atom_distance, minimum_length=0, maximum_length=1.5): + if atom_distance > minimum_length and atom_distance <= maximum_length: + return True + else: + return False + +def open_xyz(filename): + xyz_file = numpy.genfromtxt(fname=filename, skip_header=2, dtype='unicode') + symbols = xyz_file[:,0] + coord = (xyz_file[:,1:]) + coord = coord.astype(numpy.float) + return symbols, coord + +file_location = os.path.join('data', 'water.xyz') +symbols, coord = open_xyz(file_location) +num_atoms = len(symbols) +for num1 in range(0,num_atoms): + for num2 in range(0,num_atoms): + if num1 + xyzfilename = sys.argv[1] +IndexError: list index out of range +``` +{: .error} +The reason it says the list index is out of range is because `sys.argv[1]` does not exist. Since the user forgot to specify the name of the xyz file, the `sys.argv` list only has one element, `sys.argv[0]`. It would be better to print an error message and let the user know that they didn't enter the input correctly. Our code is expecting exactly two inputs: the script name and the xyz file name. The easiest way to add an error message is to check the length of the sys.argv list and print an error message and exit if it does not equal the expected length. + +While you have practiced coding, you have probably seen many error messages. We can actually raise errors in our code and write error messages to our users. +``` +if len(sys.argv) < 2: + raise NameError("Incorrect input! Please specify a file to analyze.") +``` +{: .language-python} + +This will exit the code and print our error message if the user does not specify a filename. + +There are different types of errors you can raise. For example, you may want to raise a `TypeError` if you have data that is not the right type. If you want to learn more about raising errors, [see the official documenation from Python](https://docs.python.org/3/tutorial/errors.html) + +We need to add one more thing to our code. When you write a code that includes function definitions and a main script, you need to tell python which part is the main script. (This becomes very important later when we are talking about testing.) *After* your import statements and function definitions and *before* you check the length of the `sys.argv` list add this line to your code. +``` +if __name__ == "__main__": +``` +{: .language-python} + +Since this is an `if` statement, you now need to indent each line of your main script below this if statement. Be very careful with your indentation! Don't use a mixture of tabs and spaces! + +Save your code and run it again. It should work exactly as before. If you now get an error message, it is probably due to inconsistent indentation. + +``` +import os +import numpy +import sys + +def calculate_distance(atom1_coord, atom2_coord): + x_distance = atom1_coord[0] - atom2_coord[0] + y_distance = atom1_coord[1] - atom2_coord[1] + z_distance = atom1_coord[2] - atom2_coord[2] + bond_length_12 = numpy.sqrt(x_distance**2+y_distance**2+z_distance**2) + return bond_length_12 + +def bond_check(atom_distance, minimum_length=0, maximum_length=1.5): + if atom_distance > minimum_length and atom_distance <= maximum_length: + return True + else: + return False + +def open_xyz(filename): + xyz_file = numpy.genfromtxt(fname=filename, skip_header=2, dtype='unicode') + symbols = xyz_file[:,0] + coord = (xyz_file[:,1:]) + coord = coord.astype(numpy.float) + return symbols, coord + + +if __name__ == "__main__": + + if len(sys.argv) < 2: + raise NameError("Incorrect input! Please specify a file to analyze.") + + + xyz_file = sys.argv[1] + symbols, coord = open_xyz(xyz_file) + num_atoms = len(symbols) + + for num1 in range(0,num_atoms): + for num2 in range(0,num_atoms): + if num1
-{% include carpentries.html %} +{% include molssi.html %} {% include links.md %} diff --git a/_includes/carpentries.html b/_includes/carpentries.html deleted file mode 100644 index c032bd5..0000000 --- a/_includes/carpentries.html +++ /dev/null @@ -1,70 +0,0 @@ -{% comment %} - General description of Software, Data, and Library Carpentry. -{% endcomment %} - -{% include base_path.html %} - -
-
- The Carpentries logo -
-
-

The Carpentries comprises - Software Carpentry, Data Carpentry, and Library Carpentry communities of Instructors, Trainers, - Maintainers, helpers, and supporters who share a mission to teach - foundational coding and data science skills to researchers and people - working in library- and information-related roles. In January, - 2018, The Carpentries was formed by the merger of Software Carpentry and - Data Carpentry. Library Carpentry became an official Carpentries Lesson Program in November 2018.

- -

While individual lessons and workshops continue to be run under each - lesson project, The Carpentries provide overall staffing and governance, as - well as support for assessment, instructor training and mentoring. - Memberships are joint, and the Carpentries project maintains a shared Code - of Conduct. The Carpentries is a fiscally sponsored project of Community - Initiatives, a registered 501(c)3 non-profit based in California, USA.

-
-
-
-
- Software Carpentry logo -
-
-

Since 1998, Software Carpentry has - been teaching researchers across all disciplines the foundational coding - skills they need to get more done in less time and with less pain. Its - volunteer instructors have run hundreds of events for thousands of learners - around the world. Now that all research involves some degree of - computational work, whether with big data, cloud computing, or simple task - automation, these skills are needed more than ever.

-
-
-
-
-
- Data Carpentry logo -
-
-

Data Carpentry develops and teaches - workshops on the fundamental data skills needed to conduct research. Its - target audience is researchers who have little to no prior computational - experience, and its lessons are domain specific, building on learners' - existing knowledge to enable them to quickly apply skills learned to their - own research. Data Carpentry workshops take researchers through the entire - data life cycle.

-
-
-
-
-
- Library Carpentry logo -
-
-

Library Carpentry develops lessons and - teaches workshops for and with people working in library- and - information-related roles. Its goal is to create an on-ramp to empower this - community to use software and data in their own work, as well as be - advocates for and train others in efficient, effective and reproducible data - and software practices.

-
-
diff --git a/_includes/favicons.html b/_includes/favicons.html index 8a50b4d..fb00115 100644 --- a/_includes/favicons.html +++ b/_includes/favicons.html @@ -1,4 +1,4 @@ -{% assign favicon_url = relative_root_path | append: '/assets/favicons/' | append: site.carpentry %} +{% assign favicon_url = site.baseurl | append: '/assets/favicons/' | append: site.carpentry | prepend: site.url %} {% if site.carpentry == 'swc' %} {% assign carpentry = 'Software Carpentry' %} @@ -8,26 +8,15 @@ {% assign carpentry = 'Library Carpentry' %} {% elsif site.carpentry == 'cp' %} {% assign carpentry = 'The Carpentries' %} +{% elsif site.carpentry == 'molssi' %} +{% assign carpentry = 'The Molecular Sciences Software Institute' %} {% endif %} - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/_includes/lesson_footer.html b/_includes/lesson_footer.html index 5f55b50..1f9e270 100644 --- a/_includes/lesson_footer.html +++ b/_includes/lesson_footer.html @@ -10,25 +10,25 @@
- Using The Carpentries style + Using a MolSSI modification of The Carpentries style version 9.5.0.
- + \ No newline at end of file diff --git a/_includes/molssi.html b/_includes/molssi.html new file mode 100644 index 0000000..578a3b7 --- /dev/null +++ b/_includes/molssi.html @@ -0,0 +1,29 @@ +{% comment %} + General description of The Molecular Sciences Software Institute. +{% endcomment %} +
+
+ MolSSI logo +
+
+ Since its launch in 2016, The Molecular Sciences Software Institute, has served as a nexus for the + broad computational molecular sciences community by providing software expertise, community engagement and leadership, and education + and training. Through a broad array of software infrastructure projects, teaching workshops, and community outreach, the MolSSI is + catalyzing the scientific advances needed to solve emerging scientific computing Grand Challenges. +
+
+ +
+
+

Education of students, post-docs, and faculty on programming and Best Practices in Software Development is a large part of MolSSI's mission. + Our education program consists of our cohorts of Software Fellows, + online training materials, + and multiple workshops online or in-person at various locations each year. +

+

MolSSI’s education techniques and practices are modeled after The Software Carpentries + style to teaching novice software best practices. This approach teaches subjects that not only increase a student’s scientific + capability and efficiency, but also his/her future marketability in both scientific and non-scientific fields. +

+
+
+ diff --git a/_includes/syllabus.html b/_includes/syllabus.html index 2bc607e..15dc0ca 100644 --- a/_includes/syllabus.html +++ b/_includes/syllabus.html @@ -1,5 +1,3 @@ -{% include base_path.html %} - {% comment %} Display syllabus in tabular form. Days are displayed if at least one episode has 'start = true'. @@ -19,49 +17,51 @@

Schedule

{% if multiday %}{% endif %} - Setup + Setup Download files required for the lesson {% for episode in site.episodes %} - {% if episode.start %} {% comment %} Starting a new day? {% endcomment %} - {% assign day = day | plus: 1 %} - {% if day > 1 %} {% comment %} If about to start day 2 or later, show finishing time for previous day {% endcomment %} - {% assign hours = current | divided_by: 60 %} - {% assign minutes = current | modulo: 60 %} - - {% if multiday %}{% endif %} - {% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }} - Finish - - + {% if episode.legacy == None %} + {% if episode.start %} {% comment %} Starting a new day? {% endcomment %} + {% assign day = day | plus: 1 %} + {% if day > 1 %} {% comment %} If about to start day 2 or later, show finishing time for previous day {% endcomment %} + {% assign hours = current | divided_by: 60 %} + {% assign minutes = current | modulo: 60 %} + + {% if multiday %}{% endif %} + {% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }} + Finish + + + {% endif %} + {% assign current = site.start_time %} {% comment %}Re-set start time of this episode to general daily start time {% endcomment %} {% endif %} - {% assign current = site.start_time %} {% comment %}Re-set start time of this episode to general daily start time {% endcomment %} - {% endif %} - {% assign hours = current | divided_by: 60 %} - {% assign minutes = current | modulo: 60 %} - - {% if multiday %}{% if episode.start %}Day {{ day }}{% endif %}{% endif %} - {% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }} - - {% assign lesson_number = lesson_number | plus: 1 %} - {{ lesson_number }}. {{ episode.title }} - - - {% if episode.break %} - Break - {% else %} - {% if episode.questions %} - {% for question in episode.questions %} - {{question|markdownify|strip_html}} - {% unless forloop.last %} -
- {% endunless %} - {% endfor %} + {% assign hours = current | divided_by: 60 %} + {% assign minutes = current | modulo: 60 %} + + {% if multiday %}{% if episode.start %}Day {{ day }}{% endif %}{% endif %} + {% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }} + + {% assign lesson_number = lesson_number | plus: 1 %} + {{ lesson_number }}. {{ episode.title }} + + + {% if episode.break %} + Break + {% else %} + {% if episode.questions %} + {% for question in episode.questions %} + {{question|markdownify|strip_html}} + {% unless forloop.last %} +
+ {% endunless %} + {% endfor %} + {% endif %} {% endif %} - {% endif %} - - - {% assign current = current | plus: episode.teaching | plus: episode.exercises | plus: episode.break %} + + + {% assign current = current | plus: episode.teaching | plus: episode.exercises | plus: episode.break %} + {% endif %} {% endfor %} {% assign hours = current | divided_by: 60 %} {% assign minutes = current | modulo: 60 %} @@ -77,4 +77,59 @@

Schedule

The actual schedule may vary slightly depending on the topics and exercises chosen by the instructor.

- +

Alternate Lessons

+ +

+ Alternate lessons are shown below. +

+ + + {% for episode in site.episodes %} + {% if episode.alternate %} + {% if episode.start %} {% comment %} Starting a new day? {% endcomment %} + {% assign day = day | plus: 1 %} + {% if day > 1 %} {% comment %} If about to start day 2 or later, show finishing time for previous day {% endcomment %} + {% assign hours = current | divided_by: 60 %} + {% assign minutes = current | modulo: 60 %} + + {% if multiday %}{% endif %} + + + + + {% endif %} + {% assign current = site.start_time %} {% comment %}Re-set start time of this episode to general daily start time {% endcomment %} + {% endif %} + {% assign hours = current | divided_by: 60 %} + {% assign minutes = current | modulo: 60 %} + + {% if multiday %}{% endif %} + + + + + {% assign current = current | plus: episode.teaching | plus: episode.exercises | plus: episode.break %} + {% endif %} + {% endfor %} + {% assign hours = current | divided_by: 60 %} + {% assign minutes = current | modulo: 60 %} +
{% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }}Finish
{% if episode.start %}Day {{ day }}{% endif %} + {% assign lesson_number = lesson_number | plus: 1 %} + {{ episode.title }} + + {% if episode.break %} + Break + {% else %} + {% if episode.questions %} + {% for question in episode.questions %} + {{question|markdownify|strip_html}} + {% unless forloop.last %} +
+ {% endunless %} + {% endfor %} + {% endif %} + {% endif %} +
+ + + \ No newline at end of file diff --git a/assets/css/lesson.scss b/assets/css/lesson.scss index 0401011..0b5db19 100644 --- a/assets/css/lesson.scss +++ b/assets/css/lesson.scss @@ -10,6 +10,7 @@ $color-brand: #2b3990 !default; // code boxes $color-error: #bd2c00 !default; +$color-warning: #cda01d !default; $color-output: #303030 !default; $color-source: #360084 !default; @@ -36,9 +37,10 @@ $color-testimonial: #fc8dc1 !default; border-radius: 4px 0 0 4px; } -.error { @include cdSetup($color-error); } -.output { @include cdSetup($color-output); } -.source { @include cdSetup($color-source); } +.error { @include cdSetup($color-error); } +.warning { @include cdSetup($color-warning); } +.output { @include cdSetup($color-output); } +.source { @include cdSetup($color-source); } .bash, .language-bash { @include cdSetup($color-source); } .make, .language-make { @include cdSetup($color-source); } @@ -48,6 +50,7 @@ $color-testimonial: #fc8dc1 !default; .sql, .language-sql { @include cdSetup($color-source); } .error::before, +.warning:before, .output::before, .source::before, .bash::before, .language-bash::before, @@ -56,13 +59,14 @@ $color-testimonial: #fc8dc1 !default; .python::before, .language-python::before, .r::before, .language-r::before, .sql::before, .language-sql::before { - background-color: #f2eff6; - display: block; - font-weight: bold; - padding: 5px 10px; + background-color: #f2eff6; + display: block; + font-weight: bold; + padding: 5px 10px; } .error::before { background-color: #ffebe6; content: "Error"; } +.warning:before { background-color: #f8f4e8; content:" Warning"; } .output::before { background-color: #efefef; content: "Output"; } .source::before { content: "Code"; } .bash::before, .language-bash::before { content: "Bash"; } @@ -72,7 +76,26 @@ $color-testimonial: #fc8dc1 !default; .r::before, .language-r::before { content: "R"; } .sql::before, .language-sql::before { content: "SQL"; } +// Tab panels are used on Setup pages to show instructions for different Operating Systems +.tab-pane { + border: solid 1px #ddd; // #ddd == @nav-tabs-active-link-hover-border-color + border-top: none; + padding: 20px 20px 10px 20px; + border-radius: 0 0 4px 4px; // 4px == @border-radius-base +} + +// Stripe above tab panels where OS tabs are shown +ul.nav.nav-tabs { + background: #E1E1E1; + border-radius: 4px 4px 0 0; // 4px == @border-radius-base +} +// This color provides better contrast ratio on most backgrounds used on Carpentries websites +// 9.24 on FFFFFF: https://webaim.org/resources/contrastchecker/?fcolor=204A6F&bcolor=FFFFFF&api (body) +// 8.78 on F9F9F9: https://webaim.org/resources/contrastchecker/?fcolor=204A6F&bcolor=F9F9F9&api (tables) +// 7.07 on E1E1E1: https://webaim.org/resources/contrastchecker/?fcolor=204A6F&bcolor=E1E1E1&api (tab panels) +a { color: #ed1c24FF; } +a:hover{ color: #393536ff; } //---------------------------------------- // Specialized blockquote environments for learning objectives, callouts, etc. //---------------------------------------- @@ -156,6 +179,8 @@ blockquote :not(h2) + p { // Override Bootstrap settings. //---------------------------------------- +blockquote { font-size: inherit; } + code { white-space: nowrap; padding: 2px 5px; @@ -163,6 +188,11 @@ code { background-color: #e7e7e7; } +samp { hyphens: none; } + +dt { margin-top: 20px; } +dd { margin-left: 2em; } + article img { display: block; margin: 20px auto; @@ -197,7 +227,7 @@ article pre { text-align: center; } -footer .copyright, +footer .license, footer .help-links { font-size: inherit; @@ -278,4 +308,4 @@ kbd { box-shadow: 0 1px 0 rgba(12,13,14,0.2), 0 0 0 2px #FFF inset; white-space: nowrap; font-style: normal; -} +} \ No newline at end of file diff --git a/assets/favicons/molssi/favicon-128.png b/assets/favicons/molssi/favicon-128.png new file mode 100644 index 0000000..30eab74 Binary files /dev/null and b/assets/favicons/molssi/favicon-128.png differ diff --git a/assets/favicons/molssi/favicon-152x152.png b/assets/favicons/molssi/favicon-152x152.png new file mode 100644 index 0000000..aef2b9b Binary files /dev/null and b/assets/favicons/molssi/favicon-152x152.png differ diff --git a/assets/favicons/molssi/favicon-16x16.png b/assets/favicons/molssi/favicon-16x16.png new file mode 100644 index 0000000..f24b1b2 Binary files /dev/null and b/assets/favicons/molssi/favicon-16x16.png differ diff --git a/assets/favicons/molssi/favicon-196x196.png b/assets/favicons/molssi/favicon-196x196.png new file mode 100644 index 0000000..fbc82a3 Binary files /dev/null and b/assets/favicons/molssi/favicon-196x196.png differ diff --git a/assets/favicons/molssi/favicon-32x32.png b/assets/favicons/molssi/favicon-32x32.png new file mode 100644 index 0000000..94940c2 Binary files /dev/null and b/assets/favicons/molssi/favicon-32x32.png differ diff --git a/assets/favicons/molssi/favicon-96x96.png b/assets/favicons/molssi/favicon-96x96.png new file mode 100644 index 0000000..59c3ed8 Binary files /dev/null and b/assets/favicons/molssi/favicon-96x96.png differ diff --git a/assets/favicons/molssi/molssi.jpg b/assets/favicons/molssi/molssi.jpg new file mode 100644 index 0000000..604018b Binary files /dev/null and b/assets/favicons/molssi/molssi.jpg differ