-
Notifications
You must be signed in to change notification settings - Fork 25
Creating Your Project in Drasil
Warning: Wiki should not be edited directly. Edit the files in the ./wiki/ folder instead and make a PR.
- Tips to Get Started
- Creating Your Project in Drasil
-
Adding Sections to SRS Body
- Adding Introduction Section
- Adding Specific System Description (SSD) Section
- Adding Goal Statements Section
- Adding Assumptions Section
- Adding Theoretical Models Section
- Adding General Definitions Section
- Adding Data Definitions and Acronym Section
- Adding Instance Models Section
- Adding Constraints and Properties of a Correct Solution Section
- Adding Requirements Section
- Adding Non-Functional Requirements Section
- Adding Likely and Unlikely Changes
- Adding Other Sections
- Adding Traceability Section
- Notes
- Code Generation
- You will be working mainly in the code folder.
- There are several sub-packages that you will require to create your software in Drasil.
- Many scientific theories, concepts, quantities and units commonly used in scientific problems are already coded in Drasil, you can reuse them as required. E.g Newton’s law of motion theory, units like meters, seconds, and so on. Drasil also contains concepts like gravitational acceleration, kinetic energy, velocity, and so on.
- You will be using branches and pull requests for your project. See the Contributor's Guide for more details
- In addition to this manual, you can use example projects as your cheat sheet to build your own project.
- Refer to the Haddock documentation for Drasil. A variant with fully exposed modules is also available.
- We would like to keep improving this user guide based on your feedback. Please create issue(s) on GitHub with what you think is missing, unclear, or should be included as you follow this guide. You can assign issues to @JacquesCarette or @smiths.
- Instructions on how to build a virtual machine for Linux on Windows (optional)
- Instructions on how to fork the Drasil repo and enable continuous integration. This is required to create your project in Drasil. Also check out this pull request for more information on setting up your own bot for GitHub Actions.
- Setting up your workspace
-
drasil-lang
contains language primitives focused on mathematical knowledge capture. This package also includes a language for symbols (Symbol
) and a language for mathematical expressions embedding symbols (Expr
). It describes the layout of a document and much more. -
drasil-data
contains common (reusable) knowledge such as mathematical constants and documentation concepts. You can add new concepts here. -
drasil-utils
contains common utilities used by non-drasil-lang
sub-packages. -
drasil-database
contains SystemInformation and a chunk database structure (ChunkDB
). -
drasil-docLang
contains a DSL describing the Software Requirement Specification (SRS) template. It includes a translation routine for converting to a Document DSL fromdrasil-lang
. -
drasil-theory
contains chunk types for describing refinements of mathematical theories and instantiation of definitions. -
drasil-code
contains a DSL for describing (and generating) object-oriented code. -
drasil-printers
contains set of routines to translatedrasil-lang
Documents to a common markup language such as HTML or LATEX. -
drasil-gen
defines the entry point for artefact generation. -
drasil-example
contains a set of examples maintained in Drasil to demonstrate the capabilities of the language. For consistency, you can create a sub-folder for your project here. You will be working mostly in your new subfolder. -
drasil-website
generates the homepage for the Drasil website.
Note: The instructions of this tutorial were last updated for a commit on 29 Oct 2022.
After all installation tasks and forking is completed and you are able to run existing example projects in Drasil, you are ready to create your own. You can use Visual Studio Code, Sublime or any other editor that you are familiar with.
- VS Code makes it easier to search folders and sub-folders.
- Sublime creates links to occurrences of parameters or functions used within your package and other example packages (it only create links to files open files on your machine when you point with your cursor).
-
If you are a new user, add your information
Peoples.hs
incode/drasil-data/lib/Data/Drasil/People.hs
. Create a new row and follow the same format to add your name, using the differentperson
functions as needed. -
Now, you will need to create a new sub-folder for your project. Navigate to
/code/drasil-example/
and create your new folder. -
Make a copy of template folder into the new folder and rename the new folder to your project name. Make sure you give your project an intuitive name. For example, Double Pendulum can be represented as DblPendulum, Projectile is Projectile, Solar Water Heating System is SWHS, etc. (note – project name should be one word, no spaces).
-
Import module
Data.Drasil.People
intoBody.hs
. This is the file where you added your name. This will be used to include your name as an author on your generated SRS document. E.g.import Data.Drasil.People (brenda)
-
Decide a name for your software system and define it as a Common Idea (
CI
) in a new file namedConcepts.hs
. For example, gamePhysics would be represented with:
gamePhysics :: CI
gamePhysics = commonIdeaWithDict "gamePhysics" (pn "game physics library") "Game Physics" [physics]
For more information, please see the documentation for commonIdeaWithDict
.
-
In
Body.hs
, start constructing your chunk database (ChunkDB
) in thesymbMap
function by adding your program name (e.gnw “your software name”
). Make sure the parameter you are adding here tallies with the value of the_sys
record in defined insi
inBody.hs
.si
holds all of your system's information as aSystemInformation
record type. -
Now you are ready to start constructing your SRS.
-
In your newly created project folder, open
Body.hs
. Modify the file to reflect your project name by replacing all instances of the word 'Template' with your project name. You can perform a find and replace operation to complete this. -
Go to the
si
(SystemInformation
) section of the code inBody.hs
and populate the following fields with your own functions:
_sys = example --(will become the name of your software system e.g. dblpendulum)
_authors = [authorName] --(will become the same name you added to People.hs)
For reference, the si
data is used to hold global information about a system.
si :: SystemInformation
si = SI {
_sys = example,
_kind = Doc.srs,
_authors = [authorName],
_purpose = [],
_quants = [] :: [QuantityDict],
_concepts = [] :: [DefinedQuantityDict],
_instModels = [] :: [InstanceModel],
_datadefs = [] :: [DataDefinition],
_configFiles = [],
_inputs = [] :: [QuantityDict],
_outputs = [] :: [QuantityDict],
_defSequence = [] :: [Block QDefinition],
_constraints = [] :: [ConstrainedChunk],
_constants = [] :: [QDefinition],
_sysinfodb = symbMap,
_usedinfodb = usedDB,
refdb = refDB
}
- Remember to import your software system name from
Concepts.hs
intoBody.hs
as well as all other relevant modules. Once you have done this, you may totally remove theexample
andauthorName
functions fromBody.hs
. There should be no need for these functions anymore as the second step renders them unneeded. If there are, just replace them with the ones you created.
- Update your
Main.hs
file: Your main module will load all the other modules in your project to build and generate your SRS. - Open the
Main.hs
file in the current folder and replace all instances oftemplate
with your project name, save and close.
- Start constructing your chunk database i.e
symbMap
function – As you build sections of your SRS, you will be required to fill in this database function. - Add
nw program
in the second argument ofsymbMap
, and import the module where the variableprogram
is defined i.eimport Data.Drasil.Concepts.Software (program)
.
The package.yaml
file contains some information about your project, including all the modules used in your project. From there, the compiler will generate a .cabal
file for you. The information in the .cabal
is then needed to actually build your project and connect all the packages included. As you add more modules to you project folder, you will need to update package.yaml
(which will automatically update the .cabal
file). You should almost never have to manually update the .cabal
file.
- Navigate to
../code/drasil-example/**{your-new-example-folder}**/package.yaml
- At the bottom, update the file using the other examples as a guide. It should look something like this:
...
library:
source-dirs: lib
when:
- condition: false
other-modules: Paths_{your-example-name}
executables:
yourExampleName:
main: Main
source-dirs: app
...
dependencies:
- {your-example-name}
when:
- condition: false
other-modules: Paths_{your-example-name}
- Navigate to
code/MakeFile
, add your project to the list of other example projects and modify as applicable. - Navigate to the
code
folder from git bash or your command prompt to build your project. - Run
make
to build your project. - Navigate to your project folder in
build
to view your output files. - When you build your project, both a
.tex
and.html
version of your SRS document will be auto-generated in your SRS folder. They will be separated into PDF and HTML subfolders. By now, your.html
SRS file should show a blank SRS document. - After the build operation is completed, check the output of your SRS in the
.html
file. A cascading style sheet is also autogenerated in the same folder.
You might have to update stable for all the other examples if you get the following error for any of the other examples. The one shown below is from the Template project:
-------------------------------------------
- logs/Template_log.log IS NOT EMPTY -- DIFFERENCE
- BETWEEN GENERATED AND STABLE OUTPUT FOUND
-------------------------------------------
-------------------------------------------
- ERROR IN GENERATED OUTPUT SEE ABOVE FOR -
- MORE DETAILS -
-------------------------------------------
Subsequently, you need to update stable for your new project whenever you make any changes.
-
Make a copy of your project folder from
/Drasil/code/build/yourProjectName
. -
Paste in
Drasil/code/stable
to create a folder for your project. Ensure that the version instable
matches the version inbuild
when pushing your project to your remote repository. -
Rename your folder with the name you used for
_sys
from thesi
variable inBody.hs
. This should be the same as what appeared in thebuild
folder. -
Update
.html
and.tex
files (copy and replace) only. -
When you build your project, and it says
GENERATED OUTPUT MATCHES STABLE VERSION
, then stable is up to date, no need to update. Here is what a stabilized output will look like:
----------------------------
Make complete, checking logs
----------------------------
-------------------------------------------
- GENERATED OUTPUT MATCHES STABLE VERSION -
-------------------------------------------
If you'd like to test your new project against the existing build scripts, please include [workflow-trigger]
in a commit message when pushing your work. This will force our Drasil build workflow to run on your branch, and you will be able to view logs of the run under the "Actions" tab. Alternatively, if you are working in a branch that already has a PR attached to it, it will automatically build and test without the [workflow-trigger]
in your commit message. You may then view the logs related to your test run by finding the Action run linked to your commit/PR, or by visiting the "Actions" page and looking for your triggered test run.
For more information about our automated tests, please see our Workflow documentation.
A log file will be auto-generated in a logs
folder for your project after every build: An example file path for this is: /code/logs/yourProjectName_log.log
. The logs are generated by using diff
between the build
and stable
folders to find any differences between the two folders.
- After creating a blank SRS, you will be able to add sections to it and populate with information.
- The
Body.hs
module of your project will be used to gather the sections of your SRS. - We will now begin to fill in the function
mkSRS
. The value ofmkSRS
will include all the sections required in your SRS document. Visit the different examples for more information on this. A list of potential sections and their constructors can be found in the Haddock documentation. - You will find all the sections that can be created in
../code/drasil-docLang/lib/Drasil/DocLang/SRS.hs
- Begin adding sections using the excerpt below:
mkSRS = [ TableOfContents -- Adds a Table of Contents section
RefSec $ -- Adds the reference material section
RefProg intro -- Add the introduction blob
[TUnits -- Adds table of units subsection
, tsymb [TSPurpose, TypogConvention [Vector Bold], SymbOrder, VectorUnits]
-- The above adds table of symbols with contents and specified rules e.g ordering content of table, bold vector symbols, adds purpose of document, etc.
, TAandA -- Adds table of abbreviation and acronym subsection
],
- Ensure that your import list contains DocLang's SRS:
import qualified Drasil.DocLang.SRS as SRS
-
At this point build your code (by running
make
) and see what you generate. You should see the sections in step 5 displayed in your SRS. Depending on what you have added to mkSRS you may need to update the ChunkDB first, which will be explained below. -
The remainder of the tutorial will go over adding a subset of potential sections to your project. A complete list of potential sections can be found in the Haddock documentation. Not all sections need to be included in your project.
You can add the ‘Introduction’ section and related sub-sections into Body.hs
. The SRS section builder is defined in this module:
/code/drasil-docLang/lib/Drasil/DocLang/SRS.hs
Introduction constructors can be found in the IntroSec Haddock documentation.
- Start a new section in
mkSRS
after the block you created in step 5 above. - Add the introduction section information to your project. An example Introduction will look something like:
IntroSec $
IntroProg justification (phrase dblpendulum) -- This line introduces the system you want to build. 'justification' is a function that needs to be defined in `Body.hs` to hold the content of an introduction preamble.
[IScope scope], -- This line adds the Scope of Requirements section to SRS. You will need to define a constructor for scope in Body.hs with type 'Sentence'.
- Define a
scope
constructor (example below). This will hold the content of the introduction preamble and must be aSentence
.
scope :: Sentence
scope = foldlSent [S "dblpendulum is the subject" +:+. S "dblpendulum is the focus", phrase dblpendulum]
- Define a
justification
constructor. It introduces the system you want to build.
justification :: Sentence
justification = foldlSent [ atStartNP (a_ pendulum), S "consists" `S.of_` phrase mass, ...]
- Other sub-sections similar to
scope
in step 3 can also be included e.g.Purpose
. Just make sure that you add to the imports andsymbMap
as required. Here is a sample of the first few sections added for the Projectile project:
mkSRS :: SRSDecl
mkSRS = [
RefSec $
RefProg intro
[ TUnits
, tsymb [TSPurpose, TypogConvention [Vector Bold], SymbOrder, VectorUnits]
, TAandA
],
IntroSec $
IntroProg justification (phrase projectileTitle)
[ IScope scope ],
SSDSec $
SSDProg
[ SSDProblem $ PDProg prob []
[ TermsAndDefs Nothing terms
, PhySysDesc projectileTitle physSystParts figLaunch []
, Goals [(phrase iVel +:+ S "vector") `S.the_ofThe` phrase projectile]]
- Since we added a
scope
section, you will need to include the constructor name in the chunk database.scope
is defined in thedoccon
constructor in../drasil-data/lib/Data/Drasil/Concepts/Documentation
. The process of updating the chunk database may need to be repeated for other constructors that are created in other parts of the SRS.
- In the 3rd argument of
symbMap
, add thedoccon
anddoccon'
functions. The third argument should now look like:
(nw yourSoftwarePackageName : [nw program] ++ map nw doccon ++ map nw doccon')
You must also import Data.Drasil.Concepts.Documentation as Doc (doccon, doccon')
at the top of Body.hs
.
symbMap maps references the the chunk database. Please review the GlassBR, NoPCM, and Projectile examples to understand how to populate it.
- You may choose to build your program every so often to keep track of errors easily.
SSD section constructors can be found in the SSD Haddock documentation.
-
Before you add the SSD section, you will need to define the following parameters in
Body.hs
:-
prob
(Sentence
type) defines the problem to be solved by the system. -
terms
(ConceptChunk
type) holds the terms to be defined in the terminology section. -
physSystParts
(Sentence
type) describes the physical parts of the system you intend to build.
-
-
Create a new file
Figures.hs
for your physical system diagram and define a function for your figure. A figure is only needed if adding aPhySysDesc
subsection. Otherwise, skip this step.- Add a folder for your project in
../Drasil/code/datafiles
- Save your image in your project folder
- Add your image to your function defined in
Figures.hs
- Add
Figures.hs
to your import list inBody.hs
- Add a folder for your project in
-
Add SSD section and subsections to
Body.hs
– see excerpt from a sample project below.
SSDSec $
SSDProg -- This adds a Specific system description section and an introductory blob.
[ SSDProblem $ PDProg prob [] -- This adds a is used to define the problem your system will solve
[ TermsAndDefs Nothing terms -- This is used to define the terms to be defined in terminology sub section
, PhySysDesc pendulumTitle physSystParts figMotion [] -- This defines the Physicalsystem sub-section, define the parts
-- of the system using physSysParts, figMotion is a function in figures for the image
- Add a new subsection to
mkSRS
afterPhySysDesc
so that the SSD section looks like this:
SSDSec $
SSDProg
[ SSDProblem $ PDProg prob []
[ TermsAndDefs Nothing terms
, PhySysDesc pendulumTitle physSystParts figMotion []
, Goals goalsInputs] -- This adds a goals section and goals input is defined for the preamble of the goal.
- The
goalsInputs
function defines the preamble of your goal statement. You can definegoalsInputs
inBody.hs
or in a newGoals.hs
file. For this guide, we will use a newGoals
module. - Create a new module
Goals.hs
in your working folder. - Define your goal statement using 'ConceptInstance' type.
- You will require the
goalStmtDom
concept fromData.Drasil.Concepts.Documentation
to be added to your import list in yourGoals.hs
module. You will use this function in defining your actual goal statement. YourGoals.hs
file should look something like this simplified excerpt from the Pendulum example:
module Drasil.DblPendulum.Goals (goals, goalsInputs, goalRefs) where
import Language.Drasil
import Data.Drasil.Concepts.Documentation (goalStmtDom)
goals :: [ConceptInstance]
goals = [motionMass]
goalsInputs :: [Sentence]
goalsInputs = [S "the mass and length of the rod, initial angle of the mass and the gravitational constant"]
motionMass :: ConceptInstance
motionMass = cic "motionMass"
(S "Calculate the motion of the mass")
"Motion-of-the-mass" goalStmtDom -- Here is where we apply goalStmtDom
- Add your module to the import list in
Body.hs
to display your Goal statement section and updatesymbMap
as required. - Add
goals
to yoursymbMap
or toconcIns
(which will be created in step 10 of the next section). - Add all other required parameters to your import list.
Note: Assumptions are added with the Assumptions constructor under the SSDSolChSpec constructor in the Specific System Description section.
- Declare assumptions section – Add
Assumptions
section tomakeSRS
function inBody.hs
. - Create a new module
Assumptions.hs
and add the necessary imports (Language.Drasil
, possiblyUtils.Drasil
, andassumpDom
fromData.Drasil.Concepts.Documentation
). - Determine and define your assumption functions in your assumption module. Each individual assumption should be a
ConceptInstance
type. This can be done using thecic
constructor. - Use the
assumpDom
keyword in the last argument of the definition of your assumptions.assumpDom
gives a domain (UID
) to all the assumptions defined. - Then group them together into a list named
assumptions
. E.g.
assumptions :: [ConceptInstance]
assumptions = [pend2DMotion, cartCoord, cartCoordRight, yAxisDir, startOrigin]
pend2DMotion, cartCoord, cartCoordRight, yAxisDir, startOrigin :: ConceptInstance
pend2DMotion = cic "pend2DMotion" pend2DMotionDesc "pend2DMotion" assumpDom
- Remember to import any modules used (from step 2 and from those used for defining your assumptions) into
Assumptions.hs
including:
import Data.Drasil.Concepts.Documentation (assumpDom)
- Import the
Assumptions.hs
module intoBody.hs
. - To create a section for assumption in
Body.hs
, we will need to addassumptions
tosymbMap
. An efficient way to do this is to create a function that will hold the assumptions and other sections of the SRS. So, we createconcIns
as a way of gathering these sections before putting them in oursymbMap
. Addassumptions
andgoals
toconcIns
and then addconcIns
tosymbMap
in Body.hs. Note: As you continue to build your SRS, you will add more arguments toconcIns
.
concIns :: [ConceptInstance]
concIns = assumptions ++ goals
- Run
make
to build your program.
Always remember to make references to the different parameters e.g assumptions, data definitions, theoretical models that you use throughout your project. It will help to populate your refby
field where applicable. It will also be used for your traceability graphs at the end of your document. Make sure you point to the necessary elements. Use refS
to refer to elements in your project.
Note: Theoretical Models are added with the TMs constructor under the SSDSolChSpec constructor in the Specific System Description section.
- Declare the
TM
section in yourSRSDecl
(themkSRS
function) - Define the components to be used in construction of
TM
(e.gSymbol
,Units
,DefiningEquation
) by adding an argument to define these variables. They should be of the typeFields
and look similar to this:
[ Assumptions
, TMs [] (Label : stdFields)
- Define the
stdFields
function inBody.hs
as shown below. These functions will be used in building your theoretical models and other models used in the project.
stdFields :: Fields
stdFields = [DefiningEquation, Description Verbose IncludeUnits, Notes, Source, RefBy]
- Create a new
TMods.hs
file in your project folder. - Where applicable, reuse theories from module
Data.Drasil.Theories
. - You can also define theories specific to your project by following the same format in
code/drasil-data/lib/Data/Drasil/Theories/Physics.hs
- Gather your theoretical models into a
tMods
function:
tMods :: [TheoryModel]
tMods = [theoryModel1, theoryModel2]
- Add
tMods
tosymbMap
. Also addtMods
to the last argument ofsymbMap
after mapping them through theref
function. - If you have any references for your theoretical models, add a
References.hs
file to your working folder. See example projects for sample reference module. - Import the necessary modules.
- Build your project.
- General Definitions usually include derivations of the equations used in your project. This is held by the general definition's constructor.
- You will be able to build your derivation equation and sentences and weave then together.
-
/drasil-theory/lib/Theory/Drasil
contains the constructors that will be used for constructing your general definitions.gd
andgdNoRefs
(for general definitions with no references) are the two constructors used for defining general definitions.
Note: General Definitions are added with the GDs constructor under the SSDSolChSpec constructor in the Specific System Description section.
- Add General definition section to
SRSDecl
constructor inBody.hs
as shown:
, TMs [] (Label : stdFields)
, GDs [] ([Label, Units] ++ stdFields) ShowDerivation
- Create a
Gendefs.hs
module in your working folder. This module will hold all your general definitions and derivations. - Define the functions to hold your general definitions with type
GenDefn
:
genDefns :: [GenDefn]
genDefns = [genDef1, genDef2]
- Define functions for your derivations sentences and equations.
- Add descriptions to your derivation functions and equations.
- You can use the
weave
function to connect your derivation sentences and equations to generate your derivation section for each item. Here is an excerpt from Pendulum. NoteangFrequencyDeriv
's use ofweave
:
angFrequencyDeriv :: Derivation
angFrequencyDeriv = mkDerivName (phraseNP (angularFrequency `the_ofThe` pendulum)) (weave [angFrequencyDerivSents, map eS E.angFrequencyDerivEqns])
angFrequencyDerivSents :: [Sentence]
angFrequencyDerivSents = [angFrequencyDerivSent1, angFrequencyDerivSent2, angFrequencyDerivSent3,
angFrequencyDerivSent4, angFrequencyDerivSent5, angFrequencyDerivSent6, angFrequencyDerivSent7]
angFrequencyDerivSent1, angFrequencyDerivSent2, angFrequencyDerivSent3,
angFrequencyDerivSent4, angFrequencyDerivSent5, angFrequencyDerivSent6, angFrequencyDerivSent7 :: Sentence
angFrequencyDerivSent1 = foldlSentCol [S "Consider the", phrase torque, S "on a", phrase pendulum +:+. definedIn'' newtonSLR,
S "The", phrase force, S "providing the restoring", phrase torque `S.is` phraseNP (the component `NP.of_`
(weight `ofThe` pendulum)), S "bob that acts along the" +:+. phrase arcLen,
(phrase torque `S.isThe` phrase len) `S.the_ofTheC` S "string", ch lenRod, S "multiplied by", phrase component
`S.the_ofThe` S "net", phrase force, S "that is perpendicular to", S "radius" `S.the_ofThe` (S "arc" !.),
S "The minus sign indicates the", phrase torque, S "acts in the opposite", phraseNP (direction `ofThe`angularDisplacement)]
angFrequencyDerivSent2 = S "So then"
angFrequencyDerivSent3 = S "Therefore,"
--etc.
- Add your new module to
Body.hs
to display the components of this module in the corresponding section. - Add
genDefs
tosymbMap
inBody.hs
, replacing the existing list([] :: [GenDefn])
withgenDefs
. - You might need to add another module
Unitals.hs
. You will need to define some concepts, parameters, functions or variables locally in this newUnitals.hs
module to be used specifically for your projects. These are often used in theGenDefs
module and other modules. See example projects for a better understanding of unital files. - If you have used parameters from
Unitals.hs
in yourGenDefs
module, remember to add to the import list as required. - Populate the following parameters in the
si
function (inBody.hs
) with the values defined as functions in yourUnitals
module. It should now look something like this:
_purpose = [],
_quants = symbols, -- used to define all the symbols for concepts used throughout your project
_concepts = [] :: [DefinedQuantityDict],
_instModels = iMods,
_datadefs = [],
_configFiles = [],
_inputs = inputs, -- used to define all the input variable parameters
_outputs = outputs, -- used to define all the output variable parameters
_defSequence = [] :: [Block QDefinition],
- See sample below for an example from Pendulum of defining
symbols
,inputs
, andoutputs
:
symbols :: [QuantityDict]
symbols = map qw unitalChunks ++ map qw unitless
inputs :: [QuantityDict]
inputs = map qw [LenRod, QP.force]
outputs :: [QuantityDict]
outputs = map qw [QP.position
- Add
map nw symbols
tousedDB
andsymbMap
functions inBody.hs
to display all unit symbols. - Import all the required modules.
- Build your project with
make
or the executable name in the cabal file. For example,make diff_dblpendulum
for the DblPendulum project.
Note: Data Definitions are added with the DDs constructor under the SSDSolChSpec constructor in the Specific System Description section. Acronyms are defined in a new file. Link to two examples, one with them defined in Defs and another in Unitals.
- Add data definition section to
mkSRS
inBody.hs
:
, TMs [] (Label : stdFields)
, GDs [] ([Label, Units] ++ stdFields) ShowDerivation
, DDs [] ([Label, Symbol, Units] ++ stdFields) ShowDerivation
- Add a new new module to your project folder named
DataDefs.hs
. - The constructors for creating data definitions can be found here:
/code/drasil-theory/Theory/Drasil/DataDefinition.hs
- Add the constructors to the list of imports.
- In your new module, define a list of all your general definition functions using the
DataDefinition
type. E.g
dataDefs :: [DataDefinition]
dataDefs = [positionIX, positionIY]
- Add the list function in step 6 above to
si
inBody.hs
so that the parameter is filled in like so:
_instModels = iMods,
_datadefs = [],
_configFiles = [],
- Add all parameters, symbols and units used in
dataDefs
tosymbMap
accordingly. See theBody.hs
modules from the example projects for more help. - Remember to add all symbols used in this module to symbols function in
Unitals.hs
and add to imports as applicable. - To
symbMap
, replace([] :: [UnitDefn])
with:
(map unitWrapper [{-add the units used here, ex. metre, second, etc.-}])
- If you have used acronyms (which you must, if you have created any of the above modules), create a function for the list of acronyms used. For example:
acronyms :: [CI]
acronyms = [twoD, assumption, dataDefn, genDefn, goalStmt, inModel,
physSyst, requirement, srs, thModel, typUnc]
- Add
acronyms
tosymbMap
inBody.hs
and add appropriate imports. - add
acronyms
andsymbols
tousedDB
if you have not already done so. It should look like this:
usedDB :: ChunkDB
usedDB = cdb ([] :: [QuantityDict]) (map nw acronyms ++ map nw symbols) ([] :: [ConceptChunk])
([] :: [UnitDefn]) [] [] [] [] [] [] [] ([] :: [Reference])
- Build your project.
Note: Instance Models are added with the Ims constructor under the SSDSolChSpec constructor in the Specific System Description section.
- Add the Instance Model section to
mkSRS
function inBody.hs
. It should look similar to this:
, TMs [] (Label : stdFields)
, GDs [] ([Label, Units] ++ stdFields) ShowDerivation
, DDs [] ([Label, Symbol, Units] ++ stdFields) ShowDerivation
, IMs [] ([Label, Input, Output, InConstraints, OutConstraints] ++ stdFields) ShowDerivation
- Create a new module
IMods.hs
- In
symbMap
, replace([] :: [InstanceModel])
withiMods
. - In IMods.hs, create a new function
iMods
with type[InstanceModel]
to declare your list of IM functions. E.g.
iMods :: [InstanceModel]
iMods = [iMod1, iMod2]
- Start defining your IM functions. See
/code/drasil-theory/lib/Theory/Drasil/InstanceModel.hs
for various constructors you can use in defining your instance model. Also see example projects or Haddock documentation for help. The arguments are used as follows:- Declare your IM constructor and the IM relational concept in the first argument.
- Define your input and output constraints in the next argument. Ensure that your input and output constraints are already declared or defined in your
Unitals.hs
file. - Your IMs should have derivations, declare the derivation function name and use it in the third argument.
- Declare a reference name for your IM function as a
String
in the fourth argument - You can declare a list of functions for adding notes to your IM where applicable in the fifth argument.
Your instance model will look something like this excerpt from Pendulum:
angularDisplacementIM :: InstanceModel
angularDisplacementIM = imNoRefs (OthModel angularDisplacementRC)
[qwC lenRod $ UpFrom (Exc, exactDbl 0)
,qwC initialPendAngle $ UpFrom (Exc, exactDbl 0)
, qwC gravitationalAccel $ UpFrom (Exc, exactDbl 0)]
(qw pendDisplacementAngle) [UpFrom (Exc, exactDbl 0)]
(Just angularDisplacementDeriv) "calOfAngularDisplacement" [angularDispConstraintNote]
- Define your
RelationalConcept
by defining the equation and a label for your IM. E.g
angularDisplacementRC :: RelationConcept
angularDisplacementRC = makeRC "angularDisplacementRC" (nounPhraseSP "calculation of angular displacement") -- Label goes here.
EmptyS $ apply1 pendDisplacementAngle time $= sy initialPendAngle `mulRe` cos ( sy angularFrequency `mulRe` sy time) -- Equation goes here.
- Define functions for your derivation, declared in the third argument of your instance model. You will need the weave function to combine derivation sentences and equations. See example projects for more details. Here is an excerpt from Pendulum for the top-level
angularDisplacementDeriv
function (which is used inangularDisplacementTM
as shown above):
angularDisplacementDeriv :: Derivation
angularDisplacementDeriv = mkDerivName (phrase angularDisplacement) (weave [angularDisplacementDerivSents, map eS angularDisplacementDerivEqns])
angularDisplacementDerivSents :: [Sentence]
angularDisplacementDerivSents = [angularDisplacementDerivSent1, angularDisplacementDerivSent2, angularDisplacementDerivSent3,
angularDisplacementDerivSent4, angularDisplacementDerivSent5]
- Define separate functions for your derivation sentences and equations.
- Define functions for notes where applicable, as declared in the fifth argument of your instance model. E.g.
angularDispConstraintNote :: Sentence
angularDispConstraintNote = foldlSent [atStartNP (the constraint),
eS (sy initialPendAngle $> exactDbl 0) `S.is` (S "required" !.),
atStartNP (the angularFrequency) `S.is` definedIn'' angFrequencyGD]
- Add all the required imports.
- Update
symbols
function inUnitals.hs
where applicable. - Update the chunk database (
symbMap
) as applicable.
Note: Constraints are added with the Constraints constructor and Properties of a Correct Solution are added with the CorrSolnPpties constructor under the SSDSolChSpec constructor in the Specific System Description section.
- Declare the following sections after your definition and model sections in
mkSRS
(which is inBody.hs
) as shown below:
, IMs [] ([Label, Input, Output, InConstraints, OutConstraints] ++ stdFields) ShowDerivation
, Constraints EmptyS inConstraints
, CorrSolnPpties outConstraints []
]
],
- Set
_constraints = inConstraints
insi
. - Define the functions
inConstraints
andoutConstraints
inUnitals.hs
. These functions represent constraints of your input and output parameters.- Declare constraints using the
ConstrConcept
type. - You can use constructors like
constrained'
,constrainedNRV
, etc. to create your table of constraints. See example projects for reference.
- Declare constraints using the
- Add all the required imports.
- Add all the required parameters to your chunk database in
Body.hs
.
- Declare the requirements section in
mkSRS
(inBody.hs
):
ReqrmntSec $ ReqsProg
[ FReqsSub EmptyS []
- Create a
Requirements.hs
module. - Define a list function to declare all your functional requirements. See example in the code excerpt under step 5.
- Define your requirement functions. You will need to tag every functional requirement with
funcReqDom
as shown below:
funcReqs :: [ConceptInstance]
funcReqs = [verifyInptVals, calcAngPos, outputValues]
verifyInptVals, calcAngPos, outputValues :: ConceptInstance
verifyInptVals = cic "verifyInptVals" verifyInptValsDesc "Verify-Input-Values" funcReqDom
calcAngPos = cic "calcAngPos" calcAngPosDesc "Calculate-Angular-Position-Of-Mass" funcReqDom
outputValues = cic "outputValues" outputValuesDesc "Output-Values" funcReqDom
verifyInptValsDesc, calcAngPosDesc, outputValuesDesc :: Sentence
- Define the descriptions (as
Sentences
) for your functional requirements. - Add
funcReqs
toconcIns
inBody.hs
.
concIns :: [ConceptInstance]
concIns = assumptions ++ goals ++ funcReqs
- Add all necessary modules and parameters to the list of imports.
- Declare the non-functional requirements section in
mkSRS
function inBody.hs
. The requirements declaration should now look like:
ReqrmntSec $ ReqsProg
[ FReqsSub EmptyS []
, NonFReqsSub
],
- Add non-functional requirements to
Requirements.hs
. - Define a list function with type
ConceptInstance
to declare all your non- functional requirements. See example in the code excerpt below.
nonFuncReqs :: [ConceptInstance]
nonFuncReqs = [correct, portable]
correct :: ConceptInstance
correct = cic "correct" correctDesc "Correct" nonFuncReqDom
portable :: ConceptInstance
portable = cic "portable" portableDesc "Portable" nonFuncReqDom
correctDesc, portableDesc :: Sentence
-
Define each non-functional requirement function (as
ConceptInstance
type) in the list. You will need the domainnonfuncReqDom
to define every non-functional requirement. See above code excerpt. -
Use concept instance constructor
cic
to define your non-functional requirements. Seecode/drasil-lang/Language/Drasil/Chunk/Concept.hs
for constructor info. -
Add
nonfuncReqs
toconcIns
inBody.hs
. -
Add all required parameters to import list.
-
If you have not already done so, add
srsDomains
tosymbMap (in the 3rd argument) in
Body.hs`.
Please review PDController's Body.hs to see an example of this section.
- Follow above similar steps to add likely and unlikely changes sections where applicable. See sample below.
- Add all the required imports.
- Update
concIns
function inBody.hs
to reflect likely and unlikely changes.
NonFReqsSub
],
LCsSec,
UCsSec,
Please review GamePhysics' Body.hs to see an example of this section.
- You can add other sections not included explicitly in this manual into your SRS body. For example, to add an "Off the Shelf Solution" section use:
UCsSec,
OffShelfSonsSec $ OffShelfSolnsProg offShelfSols,
For more information regarding the different possible sections, please visit the Haddock documentation for document language.
- Plug in the traceability section in mkSRS function
OffShelfSonsSec $ OffShelfSolnsProg offShelfSols,
TraceabilitySec $ TraceabilityProg $ traceMatStandard si
- Traceability graphs should now automatically generate when you build your code.
- Ensure that all the units used in your project are added to unit map in
symbMap
function. The chunk database needs to know this information to print the SRS. - Helper function to build unitals are found here:
Drasil-lang/language/Drasil/chunk/Unitals.hs
- Remember to create functions in
Unitals.hs
to store your input and output parameters. - If you have used any references, remember to below code into
Body.hs
to display your references:
refDB :: ReferenceDB
refDB = rdb citations concIns
- Reminder to add
acronymns
andsymbols
tousedDB
chunk database to display your acronymns and symbols tables:
usedDB :: ChunkDB
usedDB = cdb ([] :: [QuantityDict]) (map nw acronymn ++ map nw symbols) ([] :: [ConceptChunk])([] :: [UnitDefn]) [] [] [] [] [] [] []
- Your
mkSRS
andsi
functions should now look something like this example from Projectile:
mkSRS :: SRSDecl
mkSRS = [
RefSec $
RefProg intro
[ TUnits
, tsymb [TSPurpose, TypogConvention [Vector Bold], SymbOrder, VectorUnits]
, TAandA
],
IntroSec $
IntroProg justification (phrase projectileTitle)
[ IScope scope ],
SSDSec $
SSDProg
[ SSDProblem $ PDProg prob []
[ TermsAndDefs Nothing terms
, PhySysDesc projectileTitle physSystParts figLaunch []
, Goals [(phrase iVel +:+ S "vector") `S.the_ofThe` phrase projectile]]
, SSDSolChSpec $ SCSProg
[ Assumptions
, TMs [] (Label : stdFields)
, GDs [] ([Label, Units] ++ stdFields) ShowDerivation
, DDs [] ([Label, Symbol, Units] ++ stdFields) ShowDerivation
, IMs [] ([Label, Input, Output, InConstraints, OutConstraints] ++ stdFields) ShowDerivation
, Constraints EmptyS inConstraints
, CorrSolnPpties outConstraints []
]
],
ReqrmntSec $
ReqsProg
[ FReqsSub EmptyS []
, NonFReqsSub
],
TraceabilitySec $ TraceabilityProg $ traceMatStandard si,
AuxConstntSec $
AuxConsProg projectileTitle constants,
Bibliography
]
si :: SystemInformation
si = SI {
_sys = projectileTitle,
_kind = Doc.srs,
_authors = [samCrawford, brooks, spencerSmith],
_purpose = [],
_quants = symbols,
_concepts = [] :: [DefinedQuantityDict],
_instModels = iMods,
_datadefs = dataDefs,
_configFiles = [],
_inputs = inputs,
_outputs = outputs,
_defSequence = [] :: [Block QDefinition],
_constraints = map cnstrw constrained,
_constants = constants,
_sysinfodb = symbMap,
_usedinfodb = usedDB,
refdb = refDB
}
- Please refer to
NoPCM
orGlassBR
to generate code for your project from Drasil. - The
NoPCM
example can be referred to, if your project requires an ODE, otherwise, you can refer to theGlassBR
example. - Before you generate your code, ensure your
SystemInformation
structure is correct, particularly the inputs, outputs, relations, and constraints should be filled in and correct. - The Drasil code generator requires that you set design variabilities for your code. An overview of design variabilities can be found in Chapter 8 of this document.
- Navigate to
code/drasil-example/yourProjectName
. Then, mirror theMain.hs
file from eitherGlassBR
orNoPCM
. Also create a newChoices.hs
file and mirror that fromGlassBR
orNoPCM
. The newChoices.hs
file will let you augment your generated code depending on the choices you make. - Copy the content of the
Main.hs
file and paste in yourMain.hs
project file. Keep in mind there are some elements in the file that you already have in you yourMain.hs
file, so carefully delete duplicated or unwanted texts and modify the other content to suit your project. - Begin by modifying your design choices: see Chapter 8 of this document for more information.
- Update your import list as required in
Choices.hs
:
import Language.Drasil.Code (Choices(..), CodeSpec, codeSpec, Comments(..),
Verbosity(..), ConstraintBehaviour(..), ImplementationType(..), Lang(..),
Modularity(..), Structure(..), ConstantStructure(..), ConstantRepr(..),
InputModule(..), AuxFile(..), Visibility(..), defaultChoices)
- Implement the functions created from
Choices.hs
intoMain.hs
.GlassBR
is a great example to figure out where these functions go. - Update the
MakeFile
in thecode
folder. - You may need to use some of the following functions, so add some or all of these imports to
Body.hs
orChoices.hs
as applicable:
import Language.Drasil.Code (relToQD, quantvar, listToArray)
import Data.Drasil.ExternalLibraries.ODELibraries (scipyODESymbols, osloSymbols,
arrayVecDepVar, apacheODESymbols, odeintSymbols)
import Database.Drasil (Block(Parallel), ChunkDB, ReferenceDB,
SystemInformation(SI), cdb, rdb, refdb, _authors, _purpose, _concepts,
_constants, _constraints, _datadefs, _instModels, _configFiles, _defSequence,
_inputs, _kind, _outputs, _quants, _sys, _sysinfodb, _usedinfodb)
- Run
make
. - Your build folder should now contain a
src
folder.
- Home
- Getting Started
- Documentation (of Drasil specifics)
- Design
-
Readings
- Drasil Papers and Documents
- Related Work and Inspiration
- Writing Documentation
- Compression as a Means to Learn Structure
- Glossary, Taxonomy, Ontology
- Grounded Theory
- Model Driven Scrapbook
- Model Transformation Languages
- ODE Definitions
- The Code Generator
- Suggested Reading
- Sustainability
- Productivity
- Reuse
- Formal Concept Analysis
- Generative Programming
- Software Documentation
- Units and Quantities
- Misc.
- WIP Projects